mirror of
https://github.com/apache/superset.git
synced 2026-04-18 23:55:00 +00:00
chore(storybook): consolidate storybook and enhance plugin stories (#37771)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core';
|
||||
import { HandlebarsChartPlugin } from '@superset-ui/plugin-chart-handlebars';
|
||||
import { kpiData, leaderboardData, timelineData } from './data';
|
||||
import { withResizableChartDemo } from '@storybook-shared';
|
||||
|
||||
const VIZ_TYPE = 'handlebars';
|
||||
|
||||
new HandlebarsChartPlugin().configure({ key: VIZ_TYPE }).register();
|
||||
|
||||
getChartTransformPropsRegistry().registerValue(
|
||||
VIZ_TYPE,
|
||||
(chartProps: {
|
||||
width: number;
|
||||
height: number;
|
||||
formData: object;
|
||||
queriesData: { data: unknown[] }[];
|
||||
}) => {
|
||||
const { width, height, formData, queriesData } = chartProps;
|
||||
const { data } = queriesData[0];
|
||||
return { width, height, data, formData };
|
||||
},
|
||||
);
|
||||
|
||||
// KPI Dashboard template - uses inline styles for Storybook compatibility
|
||||
const kpiTemplate = `
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
|
||||
{{#each data}}
|
||||
<div style="background: linear-gradient(135deg, {{#if (eq status 'success')}}#11998e 0%, #38ef7d{{else}}{{#if (eq status 'warning')}}#f093fb 0%, #f5576c{{else}}#667eea 0%, #764ba2{{/if}}{{/if}} 100%); border-radius: 16px; padding: 20px; color: white; box-shadow: 0 10px 40px rgba(0,0,0,0.2);">
|
||||
<div style="font-size: 32px; margin-bottom: 12px;">{{icon}}</div>
|
||||
<div style="font-size: 12px; text-transform: uppercase; letter-spacing: 1px; opacity: 0.9;">{{metric}}</div>
|
||||
<div style="font-size: 32px; font-weight: 700; margin: 4px 0;">{{formatNumber value}}</div>
|
||||
<div style="display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px; border-radius: 12px; font-size: 12px; font-weight: 600; background: {{#if (gt change 0)}}rgba(255,255,255,0.2){{else}}rgba(0,0,0,0.15){{/if}};">
|
||||
{{#if (gt change 0)}}<span>▲</span>{{else}}<span>▼</span>{{/if}}
|
||||
{{change}}%
|
||||
</div>
|
||||
<div style="margin-top: 8px; font-size: 11px; opacity: 0.8;">Target: {{formatNumber target}}</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Leaderboard template - dark theme with inline styles
|
||||
const leaderboardTemplate = `
|
||||
<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #1a1a2e; border-radius: 16px; padding: 24px; color: #eee;">
|
||||
<h2 style="margin: 0 0 20px 0; font-size: 18px; color: #fff;">🏆 Top Performers</h2>
|
||||
{{#each data}}
|
||||
<div style="display: flex; align-items: center; padding: 12px 16px; margin: 8px 0; background: {{#if (eq rank 1)}}linear-gradient(90deg, rgba(255,215,0,0.2) 0%, transparent 100%){{else}}{{#if (eq rank 2)}}linear-gradient(90deg, rgba(192,192,192,0.2) 0%, transparent 100%){{else}}{{#if (eq rank 3)}}linear-gradient(90deg, rgba(205,127,50,0.2) 0%, transparent 100%){{else}}rgba(255,255,255,0.05){{/if}}{{/if}}{{/if}}; border-radius: 12px; {{#if (eq rank 1)}}border-left: 3px solid #ffd700;{{/if}}{{#if (eq rank 2)}}border-left: 3px solid #c0c0c0;{{/if}}{{#if (eq rank 3)}}border-left: 3px solid #cd7f32;{{/if}}">
|
||||
<div style="width: 28px; height: 28px; border-radius: 50%; background: {{#if (eq rank 1)}}#ffd700{{else}}{{#if (eq rank 2)}}#c0c0c0{{else}}{{#if (eq rank 3)}}#cd7f32{{else}}rgba(255,255,255,0.1){{/if}}{{/if}}{{/if}}; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 12px; margin-right: 12px; {{#if (lte rank 3)}}color: #1a1a2e;{{/if}}">{{rank}}</div>
|
||||
<div style="font-size: 28px; margin-right: 12px;">{{avatar}}</div>
|
||||
<div style="flex: 1;">
|
||||
<div style="font-weight: 600; font-size: 14px;">{{name}}</div>
|
||||
<div style="font-size: 11px; color: #888; margin-top: 2px;">{{team}}</div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 18px; font-weight: 700; color: #fff;">{{formatNumber score}}</div>
|
||||
<div style="font-size: 12px; margin-top: 2px; color: {{#if (eq trend 'up')}}#38ef7d{{else}}{{#if (eq trend 'down')}}#f5576c{{else}}#888{{/if}}{{/if}};">
|
||||
{{#if (eq trend 'up')}}↑{{/if}}{{#if (eq trend 'down')}}↓{{/if}}{{#if (eq trend 'same')}}→{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Timeline template with inline styles
|
||||
const timelineTemplate = `
|
||||
<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; position: relative; padding-left: 40px;">
|
||||
<div style="position: absolute; left: 13px; top: 8px; bottom: 8px; width: 3px; background: linear-gradient(180deg, #667eea 0%, #764ba2 100%); border-radius: 2px;"></div>
|
||||
{{#each data}}
|
||||
<div style="position: relative; padding: 12px 0;">
|
||||
<div style="position: absolute; left: -33px; top: 16px; width: 16px; height: 16px; border-radius: 50%; background: {{#if (eq type 'milestone')}}#ffd700{{else}}{{#if (eq type 'success')}}#38ef7d{{else}}{{#if (eq type 'warning')}}#f5576c{{else}}#667eea{{/if}}{{/if}}{{/if}}; border: 3px solid #fff; box-shadow: 0 0 0 3px {{#if (eq type 'milestone')}}rgba(255,215,0,0.3){{else}}{{#if (eq type 'success')}}rgba(56,239,125,0.3){{else}}{{#if (eq type 'warning')}}rgba(245,87,108,0.3){{else}}rgba(102,126,234,0.3){{/if}}{{/if}}{{/if}};"></div>
|
||||
<div style="background: #f8f9fa; border-radius: 12px; padding: 16px 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); margin-left: 8px;">
|
||||
<div style="font-size: 11px; color: #888; text-transform: uppercase; letter-spacing: 0.5px;">{{date}}</div>
|
||||
<div style="font-size: 16px; font-weight: 600; color: #333; margin: 4px 0;">{{event}}</div>
|
||||
<div style="font-size: 13px; color: #666; line-height: 1.4;">{{description}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Simple editable template for the interactive demo
|
||||
const simpleTemplate = `<div style="font-family: sans-serif; padding: 16px;">
|
||||
<h2 style="margin: 0 0 16px 0;">{{title}}</h2>
|
||||
<ul style="list-style: none; padding: 0; margin: 0;">
|
||||
{{#each data}}
|
||||
<li style="padding: 8px; margin: 4px 0; background: #f5f5f5; border-radius: 4px;">
|
||||
<strong>{{metric}}</strong>: {{formatNumber value}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>`;
|
||||
|
||||
// Simple CSS for the interactive demo
|
||||
const simpleCSS = `.handlebars-container {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
}
|
||||
|
||||
.handlebars-container h2 {
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.handlebars-container ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.handlebars-container li {
|
||||
padding: 12px;
|
||||
margin: 8px 0;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
}`;
|
||||
|
||||
export default {
|
||||
title: 'Chart Plugins/plugin-chart-handlebars',
|
||||
decorators: [withResizableChartDemo],
|
||||
};
|
||||
|
||||
export const InteractiveHandlebars = ({
|
||||
handlebarsTemplate,
|
||||
styleTemplate,
|
||||
width,
|
||||
height,
|
||||
}: {
|
||||
handlebarsTemplate: string;
|
||||
styleTemplate: string;
|
||||
width: number;
|
||||
height: number;
|
||||
}) => (
|
||||
<SuperChart
|
||||
chartType={VIZ_TYPE}
|
||||
width={width}
|
||||
height={height}
|
||||
queriesData={[{ data: kpiData }]}
|
||||
formData={{
|
||||
datasource: '1__table',
|
||||
viz_type: VIZ_TYPE,
|
||||
handlebars_template: handlebarsTemplate,
|
||||
style_template: styleTemplate,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
InteractiveHandlebars.args = {
|
||||
handlebarsTemplate: simpleTemplate,
|
||||
styleTemplate: simpleCSS,
|
||||
};
|
||||
|
||||
InteractiveHandlebars.argTypes = {
|
||||
handlebarsTemplate: {
|
||||
control: { type: 'text' },
|
||||
description: 'Handlebars template for rendering data',
|
||||
},
|
||||
styleTemplate: {
|
||||
control: { type: 'text' },
|
||||
description: 'CSS styles to apply to the chart',
|
||||
},
|
||||
};
|
||||
|
||||
InteractiveHandlebars.parameters = {
|
||||
initialSize: {
|
||||
width: 600,
|
||||
height: 400,
|
||||
},
|
||||
};
|
||||
|
||||
export const KPIDashboard = ({
|
||||
width,
|
||||
height,
|
||||
}: {
|
||||
width: number;
|
||||
height: number;
|
||||
}) => (
|
||||
<SuperChart
|
||||
chartType={VIZ_TYPE}
|
||||
width={width}
|
||||
height={height}
|
||||
queriesData={[{ data: kpiData }]}
|
||||
formData={{
|
||||
datasource: '1__table',
|
||||
viz_type: VIZ_TYPE,
|
||||
handlebars_template: kpiTemplate,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
KPIDashboard.parameters = {
|
||||
initialSize: {
|
||||
width: 900,
|
||||
height: 280,
|
||||
},
|
||||
};
|
||||
|
||||
export const Leaderboard = ({
|
||||
width,
|
||||
height,
|
||||
}: {
|
||||
width: number;
|
||||
height: number;
|
||||
}) => (
|
||||
<SuperChart
|
||||
chartType={VIZ_TYPE}
|
||||
width={width}
|
||||
height={height}
|
||||
queriesData={[{ data: leaderboardData }]}
|
||||
formData={{
|
||||
datasource: '1__table',
|
||||
viz_type: VIZ_TYPE,
|
||||
handlebars_template: leaderboardTemplate,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
Leaderboard.parameters = {
|
||||
initialSize: {
|
||||
width: 450,
|
||||
height: 420,
|
||||
},
|
||||
};
|
||||
|
||||
export const Timeline = ({
|
||||
width,
|
||||
height,
|
||||
}: {
|
||||
width: number;
|
||||
height: number;
|
||||
}) => (
|
||||
<SuperChart
|
||||
chartType={VIZ_TYPE}
|
||||
width={width}
|
||||
height={height}
|
||||
queriesData={[{ data: timelineData }]}
|
||||
formData={{
|
||||
datasource: '1__table',
|
||||
viz_type: VIZ_TYPE,
|
||||
handlebars_template: timelineTemplate,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
Timeline.parameters = {
|
||||
initialSize: {
|
||||
width: 500,
|
||||
height: 500,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export const kpiData = [
|
||||
{
|
||||
metric: 'Total Revenue',
|
||||
value: 2847563,
|
||||
change: 12.5,
|
||||
target: 2500000,
|
||||
icon: '💰',
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
metric: 'Active Users',
|
||||
value: 84521,
|
||||
change: -3.2,
|
||||
target: 90000,
|
||||
icon: '👥',
|
||||
status: 'warning',
|
||||
},
|
||||
{
|
||||
metric: 'Conversion Rate',
|
||||
value: 4.7,
|
||||
change: 0.8,
|
||||
target: 5.0,
|
||||
icon: '📈',
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
metric: 'Avg Response Time',
|
||||
value: 142,
|
||||
change: -15.3,
|
||||
target: 150,
|
||||
icon: '⚡',
|
||||
status: 'success',
|
||||
},
|
||||
];
|
||||
|
||||
export const leaderboardData = [
|
||||
{
|
||||
rank: 1,
|
||||
name: 'Sarah Chen',
|
||||
team: 'Engineering',
|
||||
score: 2847,
|
||||
avatar: '👩💻',
|
||||
trend: 'up',
|
||||
},
|
||||
{
|
||||
rank: 2,
|
||||
name: 'Marcus Johnson',
|
||||
team: 'Sales',
|
||||
score: 2654,
|
||||
avatar: '👨💼',
|
||||
trend: 'up',
|
||||
},
|
||||
{
|
||||
rank: 3,
|
||||
name: 'Emily Rodriguez',
|
||||
team: 'Marketing',
|
||||
score: 2432,
|
||||
avatar: '👩🎨',
|
||||
trend: 'down',
|
||||
},
|
||||
{
|
||||
rank: 4,
|
||||
name: 'David Kim',
|
||||
team: 'Engineering',
|
||||
score: 2198,
|
||||
avatar: '👨💻',
|
||||
trend: 'up',
|
||||
},
|
||||
{
|
||||
rank: 5,
|
||||
name: 'Lisa Thompson',
|
||||
team: 'Support',
|
||||
score: 2045,
|
||||
avatar: '👩🔧',
|
||||
trend: 'same',
|
||||
},
|
||||
];
|
||||
|
||||
export const timelineData = [
|
||||
{
|
||||
date: '2024-01-15',
|
||||
event: 'Product Launch',
|
||||
type: 'milestone',
|
||||
description: 'Successfully launched v2.0 to production',
|
||||
},
|
||||
{
|
||||
date: '2024-01-10',
|
||||
event: 'Beta Testing Complete',
|
||||
type: 'success',
|
||||
description: '500+ users tested with 98% satisfaction',
|
||||
},
|
||||
{
|
||||
date: '2024-01-05',
|
||||
event: 'Security Audit',
|
||||
type: 'warning',
|
||||
description: '2 minor issues found and resolved',
|
||||
},
|
||||
{
|
||||
date: '2023-12-20',
|
||||
event: 'Development Sprint',
|
||||
type: 'info',
|
||||
description: 'Completed 47 story points',
|
||||
},
|
||||
{
|
||||
date: '2023-12-15',
|
||||
event: 'Design Review',
|
||||
type: 'info',
|
||||
description: 'UI/UX approved by stakeholders',
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user