Enhance chart customization options by adding color selection, grid display, tooltip display, animation, and value formatting.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/52091063-0956-4712-acd3-7bb273cc6f8d.jpg
This commit is contained in:
alphaeusmote
2025-04-10 00:38:59 +00:00
parent 2c4733cbf0
commit 46487e7855
3 changed files with 567 additions and 500 deletions
+268 -78
View File
@@ -61,6 +61,15 @@ const widgetSchema = z.object({
showLegend: z.boolean().default(true),
stacked: z.boolean().default(false),
precision: z.number().min(0).max(10).default(2),
// New chart options
colors: z.array(z.string()).optional(),
showGrid: z.boolean().default(true),
showTooltip: z.boolean().default(true),
enableAnimation: z.boolean().default(true),
valueFormatter: z.enum(["none", "number", "percent", "currency"]).default("none"),
currencySymbol: z.string().default("$"),
minValue: z.number().nullable().default(null),
maxValue: z.number().nullable().default(null),
}),
});
@@ -100,6 +109,15 @@ export function WidgetEditor({
showLegend: editWidget?.config?.showLegend ?? true,
stacked: editWidget?.config?.stacked ?? false,
precision: editWidget?.config?.precision ?? 2,
// New chart options with defaults
colors: editWidget?.config?.colors || [],
showGrid: editWidget?.config?.showGrid ?? true,
showTooltip: editWidget?.config?.showTooltip ?? true,
enableAnimation: editWidget?.config?.enableAnimation ?? true,
valueFormatter: editWidget?.config?.valueFormatter || "none",
currencySymbol: editWidget?.config?.currencySymbol || "$",
minValue: editWidget?.config?.minValue ?? null,
maxValue: editWidget?.config?.maxValue ?? null,
},
},
});
@@ -406,89 +424,261 @@ export function WidgetEditor({
<AccordionTrigger>Chart Options</AccordionTrigger>
<AccordionContent>
<div className="space-y-4">
{/* Data Configuration section */}
{["bar", "line", "area"].includes(watchType) && (
<div className="space-y-2">
<FormField
control={form.control}
name="config.xAxis"
render={({ field }) => (
<FormItem>
<FormLabel>X-Axis Field</FormLabel>
<Select
value={field.value}
onValueChange={field.onChange}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select X-Axis field" />
</SelectTrigger>
</FormControl>
<SelectContent>
{(form.getValues('config.dimensions') || []).map((dimension) => (
<SelectItem key={dimension} value={dimension}>
{dimension}
</SelectItem>
))}
</SelectContent>
</Select>
<FormDescription>
Choose a dimension field for the X-Axis
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<div>
<FormLabel>Y-Axis Fields</FormLabel>
<div className="space-y-2 mt-2">
{(form.getValues('config.metrics') || []).map((metric) => (
<div key={metric} className="flex items-center space-x-2">
<Checkbox
checked={(form.getValues('config.yAxis') || []).includes(metric)}
onCheckedChange={(checked) => {
if (checked) {
toggleAsYAxis(metric);
} else {
toggleAsYAxis(metric);
}
}}
id={`y-axis-${metric}`}
/>
<label
htmlFor={`y-axis-${metric}`}
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
<div className="space-y-4">
<h3 className="text-sm font-medium">Data Configuration</h3>
<div className="space-y-2 border-l-2 pl-3">
<FormField
control={form.control}
name="config.xAxis"
render={({ field }) => (
<FormItem>
<FormLabel>X-Axis Field</FormLabel>
<Select
value={field.value}
onValueChange={field.onChange}
>
{metric}
</label>
</div>
))}
</div>
<FormDescription>
Select metric fields to display on the Y-Axis
</FormDescription>
</div>
<FormField
control={form.control}
name="config.stacked"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between">
<div className="space-y-0.5">
<FormLabel className="text-sm">Stacked Chart</FormLabel>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select X-Axis field" />
</SelectTrigger>
</FormControl>
<SelectContent>
{(form.getValues('config.dimensions') || []).map((dimension) => (
<SelectItem key={dimension} value={dimension}>
{dimension}
</SelectItem>
))}
</SelectContent>
</Select>
<FormDescription>
Stack the values on top of each other
Choose a dimension field for the X-Axis
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
<FormMessage />
</FormItem>
)}
/>
<div>
<FormLabel>Y-Axis Fields</FormLabel>
<div className="space-y-2 mt-2">
{(form.getValues('config.metrics') || []).map((metric) => (
<div key={metric} className="flex items-center space-x-2">
<Checkbox
checked={(form.getValues('config.yAxis') || []).includes(metric)}
onCheckedChange={(checked) => {
if (checked) {
toggleAsYAxis(metric);
} else {
toggleAsYAxis(metric);
}
}}
id={`y-axis-${metric}`}
/>
<label
htmlFor={`y-axis-${metric}`}
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
{metric}
</label>
</div>
))}
</div>
<FormDescription>
Select metric fields to display on the Y-Axis
</FormDescription>
</div>
<FormField
control={form.control}
name="config.stacked"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between">
<div className="space-y-0.5">
<FormLabel className="text-sm">Stacked Chart</FormLabel>
<FormDescription>
Stack the values on top of each other
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
</div>
{/* Display Options section */}
<h3 className="text-sm font-medium">Display Options</h3>
<div className="space-y-4 border-l-2 pl-3">
{/* Show/Hide Grid Lines */}
<FormField
control={form.control}
name="config.showGrid"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between">
<div className="space-y-0.5">
<FormLabel className="text-sm">Show Grid Lines</FormLabel>
<FormDescription>
Display grid lines in the chart background
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
{/* Show/Hide Tooltip */}
<FormField
control={form.control}
name="config.showTooltip"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between">
<div className="space-y-0.5">
<FormLabel className="text-sm">Show Tooltip</FormLabel>
<FormDescription>
Display tooltip when hovering over data points
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
{/* Enable Animation */}
<FormField
control={form.control}
name="config.enableAnimation"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between">
<div className="space-y-0.5">
<FormLabel className="text-sm">Enable Animation</FormLabel>
<FormDescription>
Animate chart when loading data
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
{/* Value Formatter */}
<FormField
control={form.control}
name="config.valueFormatter"
render={({ field }) => (
<FormItem>
<FormLabel>Value Format</FormLabel>
<Select
value={field.value}
onValueChange={field.onChange}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select value format" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="none">No formatting</SelectItem>
<SelectItem value="number">Number with commas</SelectItem>
<SelectItem value="percent">Percentage</SelectItem>
<SelectItem value="currency">Currency</SelectItem>
</SelectContent>
</Select>
<FormDescription>
Format for displaying values in the chart
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
{/* Currency Symbol (only if valueFormatter is 'currency') */}
{form.watch('config.valueFormatter') === 'currency' && (
<FormField
control={form.control}
name="config.currencySymbol"
render={({ field }) => (
<FormItem>
<FormLabel>Currency Symbol</FormLabel>
<FormControl>
<Input placeholder="$" {...field} />
</FormControl>
<FormDescription>
Symbol to display before values (e.g., $, , £)
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
)}
/>
</div>
{/* Axis Limits */}
<h3 className="text-sm font-medium">Axis Limits</h3>
<div className="grid grid-cols-2 gap-3 border-l-2 pl-3">
<FormField
control={form.control}
name="config.minValue"
render={({ field }) => (
<FormItem>
<FormLabel>Min Value</FormLabel>
<FormControl>
<Input
type="number"
placeholder="Auto"
value={field.value !== null ? field.value : ''}
onChange={(e) => field.onChange(e.target.value === '' ? null : Number(e.target.value))}
/>
</FormControl>
<FormDescription>
Minimum value for Y-axis (optional)
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="config.maxValue"
render={({ field }) => (
<FormItem>
<FormLabel>Max Value</FormLabel>
<FormControl>
<Input
type="number"
placeholder="Auto"
value={field.value !== null ? field.value : ''}
onChange={(e) => field.onChange(e.target.value === '' ? null : Number(e.target.value))}
/>
</FormControl>
<FormDescription>
Maximum value for Y-axis (optional)
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
)}