From fde963f82a2061b4bbfa83c3b936541d8213dcba Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 7 Nov 2025 16:28:51 +0000
Subject: [PATCH 1/7] Initial plan
From a06048997b6dba074c7b9cae33398c69d859d918 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 7 Nov 2025 16:37:13 +0000
Subject: [PATCH 2/7] feat: create ten pre-built widgets and implement gallery
page
- Created 10 beautiful pre-built widgets using basic components:
1. User Profile Card - profile with avatar, stats, and actions
2. Task List Item - task with priority badge and progress
3. Notification Card - activity notifications with timestamps
4. Weather Widget - current weather with forecast details
5. Stats Dashboard Card - metrics with trend indicators
6. Product Card - e-commerce product with image and details
7. Music Player - compact player with album art and controls
8. Social Media Post - post card with engagement metrics
9. Calendar Event - meeting/event card with participants
10. Email Preview - email card with sender info and actions
- Implemented gallery page with:
- Grid layout displaying all widgets
- Interactive preview of each widget
- Dialog showing widget's JSX template with syntax highlighting
- "Use This Widget" button to create and edit widget in editor
- Navigation integration with sidebar menu
Co-authored-by: foreleven <4785594+foreleven@users.noreply.github.com>
---
.../src/pages/gallery/WidgetGallery.tsx | 166 +++++++++++++++++-
.../pages/gallery/widgets/calendar-event.ts | 70 ++++++++
.../pages/gallery/widgets/email-preview.ts | 64 +++++++
.../src/pages/gallery/widgets/index.ts | 30 ++++
.../src/pages/gallery/widgets/music-player.ts | 50 ++++++
.../gallery/widgets/notification-card.ts | 37 ++++
.../src/pages/gallery/widgets/product-card.ts | 51 ++++++
.../gallery/widgets/social-media-post.ts | 66 +++++++
.../pages/gallery/widgets/stats-dashboard.ts | 47 +++++
.../pages/gallery/widgets/task-list-item.ts | 57 ++++++
.../gallery/widgets/user-profile-card.ts | 61 +++++++
.../pages/gallery/widgets/weather-widget.ts | 56 ++++++
.../src/pages/layout/AppSidebar.tsx | 10 +-
13 files changed, 763 insertions(+), 2 deletions(-)
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/calendar-event.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/email-preview.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/index.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/music-player.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/notification-card.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/product-card.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/social-media-post.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/stats-dashboard.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/task-list-item.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/user-profile-card.ts
create mode 100644 apps/widget-builder/src/pages/gallery/widgets/weather-widget.ts
diff --git a/apps/widget-builder/src/pages/gallery/WidgetGallery.tsx b/apps/widget-builder/src/pages/gallery/WidgetGallery.tsx
index 9a0463e..03682b6 100644
--- a/apps/widget-builder/src/pages/gallery/WidgetGallery.tsx
+++ b/apps/widget-builder/src/pages/gallery/WidgetGallery.tsx
@@ -1,3 +1,167 @@
+import { WidgetRenderer } from "@deer-flow/widget-renderer";
+import { Code2, Sparkles } from "lucide-react";
+import { useState } from "react";
+import { useNavigate } from "react-router-dom";
+import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
+import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism";
+
+import { ErrorBoundary } from "@/components/ErrorBoundary";
+import { Button } from "@/components/ui/button";
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { ScrollArea } from "@/components/ui/scroll-area";
+import { components } from "@/components/widget-components";
+import { useWidgets } from "@/hooks/use-widgets";
+
+import { galleryWidgets } from "./widgets";
+
export const WidgetGallery = () => {
- return
Widget Gallery Page
;
+ const navigate = useNavigate();
+ const { createWidget } = useWidgets();
+ const [selectedWidget, setSelectedWidget] = useState(null);
+ const [isDialogOpen, setIsDialogOpen] = useState(false);
+
+ const handleWidgetClick = (index: number) => {
+ setSelectedWidget(index);
+ setIsDialogOpen(true);
+ };
+
+ const handleUseWidget = () => {
+ if (selectedWidget === null) return;
+
+ const widget = galleryWidgets[selectedWidget].widget;
+ const newWidget = createWidget(widget);
+ setIsDialogOpen(false);
+ navigate(`/editor/${newWidget.id}`);
+ };
+
+ return (
+
+ {/* Header */}
+
+
+
+
Widget Gallery
+
+
+ {galleryWidgets.length} pre-built widgets ready to use
+
+
+
+ {/* Gallery Grid */}
+
+
+
+ {galleryWidgets.map((item, index) => (
+
handleWidgetClick(index)}
+ >
+
+ {/* Widget Preview */}
+
+
+ {/* Widget Info */}
+
+
{item.widget.name}
+
+ {item.widget.description}
+
+
+
+ {/* Hover Overlay */}
+
+
+
+
+
+ ))}
+
+
+
+
+ {/* Widget Details Dialog */}
+
+
+ );
};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/calendar-event.ts b/apps/widget-builder/src/pages/gallery/widgets/calendar-event.ts
new file mode 100644
index 0000000..31adeae
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/calendar-event.ts
@@ -0,0 +1,70 @@
+import { Widget } from "@deer-flow/widget";
+
+export const calendarEvent: Omit = {
+ name: "Calendar Event",
+ description: "An event card showing meeting details and participants",
+ template: `
+
+
+
+ {data.month}
+ {data.day}
+
+
+
+
+ {data.title}
+
+ 🕐 {data.time}
+ 📍 {data.location}
+
+
+
+
+
+
+
+ {data.description}
+
+
+ Participants:
+
+ {data.participants.map((participant, i) => (
+
+ ))}
+
+ +{data.moreParticipants}
+
+
+
+
+
+
+
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ month: "NOV",
+ day: "15",
+ title: "Team Sync Meeting",
+ time: "2:00 PM - 3:00 PM",
+ location: "Conference Room A",
+ description: "Weekly team sync to discuss project progress and upcoming milestones",
+ participants: [
+ { avatar: "https://i.pravatar.cc/150?img=6" },
+ { avatar: "https://i.pravatar.cc/150?img=7" },
+ { avatar: "https://i.pravatar.cc/150?img=8" }
+ ],
+ moreParticipants: "5"
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/email-preview.ts b/apps/widget-builder/src/pages/gallery/widgets/email-preview.ts
new file mode 100644
index 0000000..85a9604
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/email-preview.ts
@@ -0,0 +1,64 @@
+import { Widget } from "@deer-flow/widget";
+
+export const emailPreview: Omit = {
+ name: "Email Preview",
+ description: "An email preview card with sender info and quick actions",
+ template: `
+
+
+
+
+ {data.sender.name}
+ {data.unread && New}
+
+ {data.sender.email}
+
+
+ {data.time}
+
+
+
+ {data.subject}
+
+
+
+ {data.preview}
+
+
+ {data.hasAttachment && (
+
+ 📎
+ {data.attachmentCount} attachment{data.attachmentCount > 1 ? "s" : ""}
+
+ )}
+
+
+
+
+
+
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ sender: {
+ name: "Emma Wilson",
+ email: "emma@company.com",
+ avatar: "https://i.pravatar.cc/150?img=9"
+ },
+ subject: "Q4 Marketing Strategy Review",
+ preview: "Hi team, I've prepared the Q4 marketing strategy document. Please review the attached presentation and share your feedback before Friday's meeting...",
+ time: "10:30 AM",
+ unread: true,
+ hasAttachment: true,
+ attachmentCount: 2
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/index.ts b/apps/widget-builder/src/pages/gallery/widgets/index.ts
new file mode 100644
index 0000000..874fcb2
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/index.ts
@@ -0,0 +1,30 @@
+import { Widget } from "@deer-flow/widget";
+
+import { calendarEvent } from "./calendar-event";
+import { emailPreview } from "./email-preview";
+import { musicPlayer } from "./music-player";
+import { notificationCard } from "./notification-card";
+import { productCard } from "./product-card";
+import { socialMediaPost } from "./social-media-post";
+import { statsDashboard } from "./stats-dashboard";
+import { taskListItem } from "./task-list-item";
+import { userProfileCard } from "./user-profile-card";
+import { weatherWidget } from "./weather-widget";
+
+export interface GalleryWidget {
+ widget: Omit;
+ thumbnail?: string;
+}
+
+export const galleryWidgets: GalleryWidget[] = [
+ { widget: userProfileCard },
+ { widget: taskListItem },
+ { widget: notificationCard },
+ { widget: weatherWidget },
+ { widget: statsDashboard },
+ { widget: productCard },
+ { widget: musicPlayer },
+ { widget: socialMediaPost },
+ { widget: calendarEvent },
+ { widget: emailPreview },
+];
diff --git a/apps/widget-builder/src/pages/gallery/widgets/music-player.ts b/apps/widget-builder/src/pages/gallery/widgets/music-player.ts
new file mode 100644
index 0000000..a3bde62
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/music-player.ts
@@ -0,0 +1,50 @@
+import { Widget } from "@deer-flow/widget";
+
+export const musicPlayer: Omit = {
+ name: "Music Player",
+ description: "A compact music player widget with controls",
+ template: `
+
+
+
+ {data.title}
+ {data.artist}
+ {data.album}
+
+
+
+
+
+
+ {data.currentTime}
+ {data.duration}
+
+
+
+
+
+
+
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ albumArt: "https://images.unsplash.com/photo-1470225620780-dba8ba36b745?w=400",
+ title: "Midnight Dreams",
+ artist: "Luna Rivers",
+ album: "Neon Nights",
+ currentTime: "2:34",
+ duration: "4:12",
+ progress: 62,
+ playing: true
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/notification-card.ts b/apps/widget-builder/src/pages/gallery/widgets/notification-card.ts
new file mode 100644
index 0000000..bd62340
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/notification-card.ts
@@ -0,0 +1,37 @@
+import { Widget } from "@deer-flow/widget";
+
+export const notificationCard: Omit = {
+ name: "Notification Card",
+ description: "A notification card showing activity updates with timestamp",
+ template: `
+
+
+ {data.icon}
+
+
+
+
+ {data.title}
+
+ {data.type}
+
+
+ {data.message}
+ {data.timestamp}
+
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ icon: "✓",
+ title: "Deployment Successful",
+ message: "Your application has been deployed to production",
+ type: "success",
+ timestamp: "2 minutes ago"
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/product-card.ts b/apps/widget-builder/src/pages/gallery/widgets/product-card.ts
new file mode 100644
index 0000000..09493e4
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/product-card.ts
@@ -0,0 +1,51 @@
+import { Widget } from "@deer-flow/widget";
+
+export const productCard: Omit = {
+ name: "Product Card",
+ description: "An e-commerce product card with image, details, and actions",
+ template: `
+
+
+
+
+ {data.category}
+
+ ★
+ {data.rating}
+
+
+
+
+ {data.name}
+ {data.description}
+
+
+
+
+ {data.price}
+ {data.oldPrice && {data.oldPrice}}
+
+
+
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ image: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=400",
+ name: "Wireless Headphones",
+ description: "Premium noise-cancelling headphones with 30h battery life",
+ category: "Audio",
+ price: "$299",
+ oldPrice: "$399",
+ rating: "4.8"
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/social-media-post.ts b/apps/widget-builder/src/pages/gallery/widgets/social-media-post.ts
new file mode 100644
index 0000000..ff630e5
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/social-media-post.ts
@@ -0,0 +1,66 @@
+import { Widget } from "@deer-flow/widget";
+
+export const socialMediaPost: Omit = {
+ name: "Social Media Post",
+ description: "A social media post card with engagement metrics",
+ template: `
+
+
+
+ {data.author.name}
+ {data.timestamp}
+
+
+
+
+
+
+ {data.content}
+
+
+ {data.image && }
+
+
+
+
+
+ ❤️
+ {data.likes}
+
+
+ 💬
+ {data.comments}
+
+
+ ↗️
+ {data.shares}
+
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ author: {
+ name: "Alex Johnson",
+ avatar: "https://i.pravatar.cc/150?img=5"
+ },
+ timestamp: "2 hours ago",
+ content: "Just launched our new product! Excited to share this journey with you all. 🚀",
+ image: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=600",
+ likes: "234",
+ comments: "45",
+ shares: "12"
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/stats-dashboard.ts b/apps/widget-builder/src/pages/gallery/widgets/stats-dashboard.ts
new file mode 100644
index 0000000..74746f3
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/stats-dashboard.ts
@@ -0,0 +1,47 @@
+import { Widget } from "@deer-flow/widget";
+
+export const statsDashboard: Omit = {
+ name: "Stats Dashboard Card",
+ description: "A statistics dashboard card with metrics and trend indicators",
+ template: `
+
+
+ Total Revenue
+ {data.value}
+
+
+ {data.trend === "up" ? "↑" : "↓"} {data.change}
+
+
+
+
+
+
+
+ This Month
+ {data.thisMonth}
+ +{data.monthGrowth}% from last month
+
+
+
+ Goal
+ {data.goal}
+
+
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ value: "$45,231",
+ trend: "up",
+ change: "12.5%",
+ thisMonth: "$12,450",
+ monthGrowth: "18",
+ goal: "$15,000",
+ progress: 83
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/task-list-item.ts b/apps/widget-builder/src/pages/gallery/widgets/task-list-item.ts
new file mode 100644
index 0000000..5f45295
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/task-list-item.ts
@@ -0,0 +1,57 @@
+import { Widget } from "@deer-flow/widget";
+
+export const taskListItem: Omit = {
+ name: "Task List Item",
+ description: "An elegant task list item with priority badge and due date",
+ template: `
+
+
+
+ {data.priority}
+
+
+
+
+ {data.title}
+ {data.description}
+
+
+
+
+
+ Due Date
+ {data.dueDate}
+
+
+
+
+
+
+
+ {data.assignee.name}
+
+
+ {data.progress}%
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ title: "Redesign Landing Page",
+ description: "Update the homepage with new branding and animations",
+ priority: "high",
+ dueDate: "Nov 12",
+ progress: 65,
+ assignee: {
+ name: "Mike Chen",
+ avatar: "https://i.pravatar.cc/150?img=3"
+ }
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/user-profile-card.ts b/apps/widget-builder/src/pages/gallery/widgets/user-profile-card.ts
new file mode 100644
index 0000000..9a7cf21
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/user-profile-card.ts
@@ -0,0 +1,61 @@
+import { Widget } from "@deer-flow/widget";
+
+export const userProfileCard: Omit = {
+ name: "User Profile Card",
+ description: "A beautiful user profile card with avatar, name, and social stats",
+ template: `
+
+
+
+ {data.name}
+ {data.role}
+ {data.location}
+
+
+
+
+
+
+
+ {data.stats.followers}
+ Followers
+
+
+ {data.stats.following}
+ Following
+
+
+ {data.stats.posts}
+ Posts
+
+
+
+
+
+
+
+
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ avatar: "https://i.pravatar.cc/150?img=1",
+ name: "Sarah Anderson",
+ role: "Product Designer",
+ location: "San Francisco, CA",
+ stats: {
+ followers: "2.4K",
+ following: "486",
+ posts: "127"
+ }
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/gallery/widgets/weather-widget.ts b/apps/widget-builder/src/pages/gallery/widgets/weather-widget.ts
new file mode 100644
index 0000000..14cefc3
--- /dev/null
+++ b/apps/widget-builder/src/pages/gallery/widgets/weather-widget.ts
@@ -0,0 +1,56 @@
+import { Widget } from "@deer-flow/widget";
+
+export const weatherWidget: Omit = {
+ name: "Weather Widget",
+ description: "Current weather conditions with forecast",
+ template: `
+
+
+
+ {data.location}
+ {data.date}
+
+ {data.icon}
+
+
+
+ {data.temperature}
+ °C
+
+
+ {data.condition}
+
+
+
+
+
+ Humidity
+ {data.humidity}%
+
+
+ Wind
+ {data.wind} km/h
+
+
+ Feels Like
+ {data.feelsLike}°
+
+
+
+`,
+ states: [
+ {
+ name: "Default",
+ data: {
+ location: "San Francisco",
+ date: "Monday, Nov 7",
+ icon: "☀️",
+ temperature: "22",
+ condition: "Sunny",
+ humidity: "65",
+ wind: "12",
+ feelsLike: "24"
+ }
+ }
+ ]
+};
diff --git a/apps/widget-builder/src/pages/layout/AppSidebar.tsx b/apps/widget-builder/src/pages/layout/AppSidebar.tsx
index 42e9ea2..6591d37 100644
--- a/apps/widget-builder/src/pages/layout/AppSidebar.tsx
+++ b/apps/widget-builder/src/pages/layout/AppSidebar.tsx
@@ -1,4 +1,4 @@
-import { LayoutTemplate, PlusCircleIcon, Package } from "lucide-react";
+import { LayoutTemplate, PlusCircleIcon, Package, Sparkles } from "lucide-react";
import { Link } from "react-router-dom";
import {
@@ -51,6 +51,14 @@ export function AppSidebar() {
+
+
+
+
+ Gallery
+
+
+
From 20254aee35ea2733e8ab9a46fff9d2fa7f3236e4 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 7 Nov 2025 16:44:12 +0000
Subject: [PATCH 3/7] refactor: improve code quality based on review feedback
- Extract selectedWidgetData to reduce duplication in dialog rendering
- Use computed variable instead of repeated null checks and array access
- Improve code readability and maintainability
Co-authored-by: foreleven <4785594+foreleven@users.noreply.github.com>
---
.../src/pages/gallery/WidgetGallery.tsx | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/apps/widget-builder/src/pages/gallery/WidgetGallery.tsx b/apps/widget-builder/src/pages/gallery/WidgetGallery.tsx
index 03682b6..71be9c9 100644
--- a/apps/widget-builder/src/pages/gallery/WidgetGallery.tsx
+++ b/apps/widget-builder/src/pages/gallery/WidgetGallery.tsx
@@ -41,6 +41,8 @@ export const WidgetGallery = () => {
navigate(`/editor/${newWidget.id}`);
};
+ const selectedWidgetData = selectedWidget !== null ? galleryWidgets[selectedWidget] : null;
+
return (
{/* Header */}
@@ -105,12 +107,8 @@ export const WidgetGallery = () => {