From a5149e460f146ec2b826da12760aa0808dd6b095 Mon Sep 17 00:00:00 2001 From: krut_ni Date: Mon, 9 Mar 2026 13:23:35 +0100 Subject: [PATCH] added a new color picker component to the lua parsing --- .../Assistants/Dynamic/AssistantDynamic.razor | 23 +++++++ .../Dynamic/AssistantDynamic.razor.cs | 39 ++++++++++- .../Plugins/assistants/README.md | 41 +++++++++++- .../Plugins/assistants/plugin.lua | 13 ++++ .../Assistants/AssistantComponentFactory.cs | 2 + .../DataModel/AssistantColorPicker.cs | 67 +++++++++++++++++++ .../DataModel/AssistantComponentType.cs | 1 + .../DataModel/ComponentPropSpecs.cs | 4 ++ 8 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantColorPicker.cs diff --git a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor index 171348e1..dcf10de3 100644 --- a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor +++ b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor @@ -135,5 +135,28 @@ } break; + case AssistantComponentType.COLOR_PICKER: + if (component is AssistantColorPicker assistantColorPicker) + { + var colorPicker = assistantColorPicker; + var variant = this.GetPickerVariant(colorPicker.PickerVariant); + var elevation = variant == PickerVariant.Static ? 6 : 0; + var rounded = variant == PickerVariant.Static; + + + + + } + break; } } diff --git a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor.cs b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor.cs index 1ad79708..5e3cd44b 100644 --- a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor.cs +++ b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor.cs @@ -45,6 +45,7 @@ public partial class AssistantDynamic : AssistantBaseCore private Dictionary switchFields = new(); private Dictionary webContentFields = new(); private Dictionary fileContentFields = new(); + private Dictionary colorPickerFields = new(); private readonly Dictionary imageCache = new(); private string pluginPath = string.Empty; private const string PLUGIN_SCHEME = "plugin://"; @@ -111,6 +112,12 @@ public partial class AssistantDynamic : AssistantBaseCore this.fileContentFields.Add(fileContent.Name, new FileContentState()); } break; + case AssistantComponentType.COLOR_PICKER: + if (component is AssistantColorPicker assistantColorPicker) + { + this.colorPickerFields.Add(assistantColorPicker.Name, assistantColorPicker.Placeholder); + } + break; } } } @@ -167,6 +174,11 @@ public partial class AssistantDynamic : AssistantBaseCore { entry.Value.Content = string.Empty; } + + foreach (var entry in this.colorPickerFields) + { + this.colorPickerFields[entry.Key] = string.Empty; + } } protected override bool MightPreselectValues() @@ -256,6 +268,8 @@ public partial class AssistantDynamic : AssistantBaseCore fields[entry.Key] = entry.Value.Content ?? string.Empty; foreach (var entry in this.fileContentFields) fields[entry.Key] = entry.Value.Content ?? string.Empty; + foreach (var entry in this.colorPickerFields) + fields[entry.Key] = entry.Value ?? string.Empty; input["fields"] = fields; @@ -282,6 +296,9 @@ public partial class AssistantDynamic : AssistantBaseCore case AssistantFileContentReader fileContent: this.AddMetaEntry(meta, fileContent.Name, component.Type, null, fileContent.UserPrompt); break; + case AssistantColorPicker colorPicker: + this.AddMetaEntry(meta, colorPicker.Name, component.Type, colorPicker.Label, colorPicker.UserPrompt); + break; } } } @@ -391,6 +408,16 @@ public partial class AssistantDynamic : AssistantBaseCore } } break; + case AssistantComponentType.COLOR_PICKER: + if (component is AssistantColorPicker colorPicker) + { + prompt += $"context:{Environment.NewLine}{colorPicker.UserPrompt}{Environment.NewLine}---{Environment.NewLine}"; + if (this.inputFields.TryGetValue(colorPicker.Name, out userInput)) + { + prompt += $"user prompt:{Environment.NewLine}{userInput}"; + } + } + break; default: prompt += $"{userInput}{Environment.NewLine}"; break; @@ -414,8 +441,16 @@ public partial class AssistantDynamic : AssistantBaseCore } private string? GetOptionalStyle(string? style) => string.IsNullOrWhiteSpace(style) ? null : style; - - private string? ValidateProfileSelection(AssistantProfileSelection profileSelection, Profile profile) + + private PickerVariant GetPickerVariant(string pickerVariant) => pickerVariant.ToLowerInvariant() switch + { + "dialog" => PickerVariant.Dialog, + "static" => PickerVariant.Static, + "inline" => PickerVariant.Inline, + _ => PickerVariant.Static + }; + + private string? ValidateProfileSelection(AssistantProfileSelection profileSelection, Profile? profile) { if (profile == default || profile == Profile.NO_PROFILE) { diff --git a/app/MindWork AI Studio/Plugins/assistants/README.md b/app/MindWork AI Studio/Plugins/assistants/README.md index 76e457e9..aa3e993b 100644 --- a/app/MindWork AI Studio/Plugins/assistants/README.md +++ b/app/MindWork AI Studio/Plugins/assistants/README.md @@ -12,6 +12,7 @@ Supported types (matching the Blazor UI components): - `TEXT_AREA`: any user input field with `Name`, `Label`, `UserPrompt`, `PrefillText`, `IsSingleLine`, `ReadOnly`. - `DROPDOWN`: selects between variants; `Props` must include `Name`, `Label`, `Default`, `Items`, and optionally `ValueType` plus `UserPrompt`. - `SWITCH`: boolean option; requires `Name`, `Label`, `Value`, `LabelOn`, `LabelOff`, and may include `UserPrompt`. +- `COLOR_PICKER`: color input based on `MudColorPicker`; requires `Name`, `Label`, and may include `Placeholder`, `ShowAlpha`, `ShowToolbar`, `ShowModeSwitch`, `PickerVariant`, `UserPrompt`, `Class`, `Style`. - `PROVIDER_SELECTION` / `PROFILE_SELECTION`: hooks into the shared provider/profile selectors. - `WEB_CONTENT_READER`: renders `ReadWebContent`; include `Name`, `UserPrompt`, `Preselect`, `PreselectContentCleanerAgent`. - `FILE_CONTENT_READER`: renders `ReadFileContent`; include `Name`, `UserPrompt`. @@ -31,7 +32,7 @@ user prompt: ``` -For switches the “value” is the boolean `true/false`; for readers it is the fetched/selected content. Always provide a meaningful `UserPrompt` so the final concatenated prompt remains coherent from the LLM’s perspective. +For switches the “value” is the boolean `true/false`; for readers it is the fetched/selected content; for color pickers it is the selected color text (for example `#FFAA00` or `rgba(...)`, depending on the picker mode). Always provide a meaningful `UserPrompt` so the final concatenated prompt remains coherent from the LLM’s perspective. ### Advanced: BuildPrompt (optional) If you want full control over prompt composition, define `ASSISTANT.BuildPrompt` as a Lua function. When present, AI Studio calls it and uses its return value as the final user prompt. The default prompt assembly is skipped. @@ -46,8 +47,9 @@ The function receives a single `input` table with: - `input.fields`: values keyed by component `Name` - Text area, dropdown, and readers are strings - Switch is a boolean + - Color picker is the selected color as a string - `input.meta`: per-component metadata keyed by component `Name` - - `Type` (string, e.g. `TEXT_AREA`, `DROPDOWN`, `SWITCH`) + - `Type` (string, e.g. `TEXT_AREA`, `DROPDOWN`, `SWITCH`, `COLOR_PICKER`) - `Label` (string, when provided) - `UserPrompt` (string, when provided) - `input.profile`: selected profile data @@ -63,7 +65,7 @@ input = { }, meta = { [""] = { - Type = "", + Type = "", Label = "", UserPrompt = "" }, @@ -103,6 +105,8 @@ ASSISTANT.BuildPrompt = function(input) local value = input.fields[name] if meta.Type == "SWITCH" then table.insert(parts, name .. ": " .. tostring(value)) + elseif meta.Type == "COLOR_PICKER" and value and value ~= "" then + table.insert(parts, name .. ": " .. value) elseif value and value ~= "" then table.insert(parts, name .. ": " .. value) end @@ -111,6 +115,37 @@ ASSISTANT.BuildPrompt = function(input) end ``` +### `COLOR_PICKER` reference +- Use `Type = "COLOR_PICKER"` to render a MudBlazor color picker. +- Required props: + - `Name`: unique state key used in prompt assembly and `BuildPrompt(input.fields)`. + - `Label`: visible field label. +- Optional props: + - `Placeholder`: default color hex string (e.g. `#FF10FF`) or initial hint text. + - `ShowAlpha`: defaults to `true`; enables alpha channel editing. + - `ShowToolbar`: defaults to `true`; shows picker/grid/palette toolbar. + - `ShowModeSwitch`: defaults to `true`; allows switching between HEX/RGB(A)/HSL modes. + - `PickerVariant`: one of `DIALOG`, `INLINE`, `STATIC`; invalid or omitted values fall back to `STATIC`. + - `UserPrompt`: prompt context text for the selected color. + - `Class`, `Style`: forwarded to the rendered component for layout/styling. + +Example: +```lua +{ + ["Type"] = "COLOR_PICKER", + ["Props"] = { + ["Name"] = "accentColor", + ["Label"] = "Accent color", + ["Placeholder"] = "#FFAA00", + ["ShowAlpha"] = false, + ["ShowToolbar"] = true, + ["ShowModeSwitch"] = true, + ["PickerVariant"] = "STATIC", + ["UserPrompt"] = "Use this as the accent color for the generated design." + } +} +``` + #### Using `profile` inside BuildPrompt Profiles are optional user context (e.g., "NeedToKnow" and "Actions"). You can inject this directly into the user prompt if you want the LLM to always see it. diff --git a/app/MindWork AI Studio/Plugins/assistants/plugin.lua b/app/MindWork AI Studio/Plugins/assistants/plugin.lua index fa19e5f9..35b3133f 100644 --- a/app/MindWork AI Studio/Plugins/assistants/plugin.lua +++ b/app/MindWork AI Studio/Plugins/assistants/plugin.lua @@ -168,6 +168,19 @@ ASSISTANT = { ["UserPrompt"] = "" } }, + { + ["Type"] = "COLOR_PICKER", + ["Props"] = { + ["Name"] = "", -- required + ["Label"] = "", -- required + ["Placeholder"] = "", + ["ShowAlpha"] = true, -- weather alpha channels are shown + ["ShowToolbar"] = true, -- weather the toolbar to toggle between picker, grid or palette is shown + ["ShowModeSwitch"] = true, -- weather switch to toggle between RGB(A), HEX or HSL color mode is shown + ["PickerVariant"] = "", + ["UserPrompt"] = "", + } + }, } }, } diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantComponentFactory.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantComponentFactory.cs index b38083fe..e5078a3b 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantComponentFactory.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantComponentFactory.cs @@ -39,6 +39,8 @@ public class AssistantComponentFactory return new AssistantFileContentReader { Props = props, Children = children }; case AssistantComponentType.IMAGE: return new AssistantImage { Props = props, Children = children }; + case AssistantComponentType.COLOR_PICKER: + return new AssistantColorPicker { Props = props, Children = children }; default: LOGGER.LogError($"Unknown assistant component type!\n{type} is not a supported assistant component type"); throw new Exception($"Unknown assistant component type: {type}"); diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantColorPicker.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantColorPicker.cs new file mode 100644 index 00000000..c0030f28 --- /dev/null +++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantColorPicker.cs @@ -0,0 +1,67 @@ +namespace AIStudio.Tools.PluginSystem.Assistants.DataModel; + +internal sealed class AssistantColorPicker : AssistantComponentBase +{ + public override AssistantComponentType Type => AssistantComponentType.COLOR_PICKER; + public override Dictionary Props { get; set; } = new(); + public override List Children { get; set; } = new(); + + public string Name + { + get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Name)); + set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Name), value); + } + public string Label + { + get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Label)); + set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Label), value); + } + + public string Placeholder + { + get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Placeholder)); + set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Placeholder), value); + } + + public bool ShowAlpha + { + get => !this.Props.TryGetValue(nameof(this.ShowAlpha), out var val) || val is true; + set => this.Props[nameof(this.ShowAlpha)] = value; + } + + public bool ShowToolbar + { + get => !this.Props.TryGetValue(nameof(this.ShowToolbar), out var val) || val is true; + set => this.Props[nameof(this.ShowToolbar)] = value; + } + + public bool ShowModeSwitch + { + get => !this.Props.TryGetValue(nameof(this.ShowModeSwitch), out var val) || val is true; + set => this.Props[nameof(this.ShowModeSwitch)] = value; + } + + public string PickerVariant + { + get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.PickerVariant)); + set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.PickerVariant), value); + } + + public string UserPrompt + { + get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.UserPrompt)); + set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.UserPrompt), value); + } + + public string Class + { + get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Class)); + set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Class), value); + } + + public string Style + { + get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Style)); + set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Style), value); + } +} diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentType.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentType.cs index d7993047..d967860a 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentType.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentType.cs @@ -15,4 +15,5 @@ public enum AssistantComponentType WEB_CONTENT_READER, FILE_CONTENT_READER, IMAGE, + COLOR_PICKER, } diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/ComponentPropSpecs.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/ComponentPropSpecs.cs index 83bf73fc..c3e94f6c 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/ComponentPropSpecs.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/ComponentPropSpecs.cs @@ -57,5 +57,9 @@ public static class ComponentPropSpecs required: ["Src"], optional: ["Alt", "Caption", "Class", "Style"] ), + [AssistantComponentType.COLOR_PICKER] = new( + required: ["Name", "Label"], + optional: ["Placeholder", "ShowAlpha", "ShowToolbar", "ShowModeSwitch", "PickerVariant", "UserPrompt", "Class", "Style"] + ), }; }