Skip to content

Commit 8837f14

Browse files
authored
feat(home): expand template examples with 83 categorized templates (#3592)
* feat(home): expand template examples with 83 categorized templates - Extract template data into consts.ts with rich categorization (category, modules, tags) - Expand from 6 to 83 templates across 7 categories: sales, support, engineering, marketing, productivity, operations - Add show more/collapse UI with category groupings for non-featured templates - Add connector-powered knowledge search templates (Gmail, Slack, Notion, Jira, Linear, Salesforce, etc.) - Add platform-native templates (document summarizer, bulk data classifier, knowledge assistant, etc.) - Optimize prompts for mothership execution with explicit resource creation and integration names - Add tags field for future cross-cutting filtering by persona, pattern, and domain - React 19.2.1 → 19.2.4 upgrade * fix(home): remove WhatsApp customer notifications template * fix(home): add aria-expanded to toggle button, skip popular in expanded view * fix(home): fix category display order, add aria-label to template cards
1 parent f077751 commit 8837f14

File tree

7 files changed

+1040
-95
lines changed

7 files changed

+1040
-95
lines changed

apps/docs/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
"next": "16.1.6",
3030
"next-themes": "^0.4.6",
3131
"postgres": "^3.4.5",
32-
"react": "19.2.1",
33-
"react-dom": "19.2.1",
32+
"react": "19.2.4",
33+
"react-dom": "19.2.4",
3434
"shiki": "4.0.0",
3535
"tailwind-merge": "^3.0.2"
3636
},

apps/sim/app/workspace/[workspaceId]/home/components/template-prompts/consts.ts

Lines changed: 886 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
export type { Category, ModuleTag, Tag, TemplatePrompt } from './consts'
2+
export { CATEGORY_META, MODULE_META, TEMPLATES } from './consts'
13
export { TemplatePrompts } from './template-prompts'
Lines changed: 137 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,152 @@
1-
import type { ComponentType, SVGProps } from 'react'
1+
'use client'
2+
3+
import { useState } from 'react'
24
import Image from 'next/image'
3-
import { Search, Table } from '@/components/emcn/icons'
4-
import { GmailIcon, GoogleCalendarIcon } from '@/components/icons'
5-
import { MarkdownIcon } from '@/components/icons/document-icons'
6-
7-
interface TemplatePrompt {
8-
icon: ComponentType<SVGProps<SVGSVGElement>>
9-
title: string
10-
prompt: string
11-
image: string
5+
import { ChevronDown } from '@/components/emcn/icons'
6+
import type { Category, ModuleTag } from './consts'
7+
import { CATEGORY_META, MODULE_META, TEMPLATES } from './consts'
8+
9+
const FEATURED_TEMPLATES = TEMPLATES.filter((t) => t.featured)
10+
const EXTRA_TEMPLATES = TEMPLATES.filter((t) => !t.featured)
11+
12+
/** Group non-featured templates by category, preserving category order. */
13+
function getGroupedExtras() {
14+
const groups: { category: Category; label: string; templates: typeof TEMPLATES }[] = []
15+
const byCategory = new Map<Category, typeof TEMPLATES>()
16+
17+
for (const t of EXTRA_TEMPLATES) {
18+
const existing = byCategory.get(t.category)
19+
if (existing) {
20+
existing.push(t)
21+
} else {
22+
const arr = [t]
23+
byCategory.set(t.category, arr)
24+
}
25+
}
26+
27+
for (const [key, meta] of Object.entries(CATEGORY_META)) {
28+
const cat = key as Category
29+
if (cat === 'popular') continue
30+
const items = byCategory.get(cat)
31+
if (items?.length) {
32+
groups.push({ category: cat, label: meta.label, templates: items })
33+
}
34+
}
35+
36+
return groups
1237
}
1338

14-
const TEMPLATES: TemplatePrompt[] = [
15-
{
16-
icon: Table,
17-
title: 'Self-populating CRM',
18-
prompt:
19-
'Create a self-healing CRM table that keeps track of all my customers by integrating with my existing data sources. Schedule a recurring job every morning to automatically pull updates from all relevant data sources and keep my CRM up to date.',
20-
image: '/templates/crm-light.png',
21-
},
22-
{
23-
icon: GoogleCalendarIcon,
24-
title: 'Meeting prep agent',
25-
prompt:
26-
'Create an agent that checks my calendar each morning, pulls context on every attendee and topic, and prepares a brief for each meeting so I walk in fully prepared.',
27-
image: '/templates/meeting-prep-dark.png',
28-
},
29-
{
30-
icon: MarkdownIcon,
31-
title: 'Resolve todo list',
32-
prompt:
33-
'Create a file of all my todos then go one by one and check off every time a todo is done. Look at my calendar and see what I have to do.',
34-
image: '/templates/todo-list-light.png',
35-
},
36-
{
37-
icon: Search,
38-
title: 'Research assistant',
39-
prompt:
40-
'Build an agent that takes a topic, searches the web for the latest information, summarizes key findings, and compiles them into a clean document I can review.',
41-
image: '/templates/research-assistant-dark.png',
42-
},
43-
{
44-
icon: GmailIcon,
45-
title: 'Auto-reply agent',
46-
prompt: 'Create a Gmail agent that drafts responses to relevant emails automatically.',
47-
image: '/templates/gmail-agent-dark.png',
48-
},
49-
{
50-
icon: Table,
51-
title: 'Expense tracker',
52-
prompt:
53-
'Create a table that tracks all my expenses by pulling transactions from my connected accounts. Categorize each expense automatically and generate a weekly summary report.',
54-
image: '/templates/expense-tracker-light.png',
55-
},
56-
]
39+
const GROUPED_EXTRAS = getGroupedExtras()
40+
41+
function ModulePills({ modules }: { modules: ModuleTag[] }) {
42+
return (
43+
<div className='flex flex-wrap gap-[4px]'>
44+
{modules.map((mod) => (
45+
<span
46+
key={mod}
47+
className='rounded-full bg-[var(--surface-3)] px-[6px] py-[1px] text-[11px] text-[var(--text-secondary)]'
48+
>
49+
{MODULE_META[mod].label}
50+
</span>
51+
))}
52+
</div>
53+
)
54+
}
5755

5856
interface TemplatePromptsProps {
5957
onSelect: (prompt: string) => void
6058
}
6159

6260
export function TemplatePrompts({ onSelect }: TemplatePromptsProps) {
61+
const [expanded, setExpanded] = useState(false)
62+
6363
return (
64-
<div className='grid grid-cols-3 gap-[16px]'>
65-
{TEMPLATES.map((template) => {
66-
const Icon = template.icon
67-
return (
68-
<button
69-
key={template.title}
70-
type='button'
71-
onClick={() => onSelect(template.prompt)}
72-
className='group flex cursor-pointer flex-col text-left'
73-
>
74-
<div className='overflow-hidden rounded-[10px] border border-[var(--border-1)]'>
75-
<div className='relative h-[120px] w-full overflow-hidden'>
76-
<Image
77-
src={template.image}
78-
alt={template.title}
79-
fill
80-
unoptimized
81-
className='object-cover transition-transform duration-300 group-hover:scale-105'
82-
/>
83-
</div>
84-
<div className='flex items-center gap-[6px] border-[var(--border-1)] border-t bg-[var(--white)] px-[10px] py-[6px] dark:bg-[var(--surface-4)]'>
85-
<Icon className='h-[14px] w-[14px] shrink-0 text-[var(--text-icon)]' />
86-
<span className='font-base text-[14px] text-[var(--text-body)]'>
87-
{template.title}
88-
</span>
64+
<div className='flex flex-col gap-[24px]'>
65+
{/* Featured grid */}
66+
<div className='grid grid-cols-3 gap-[16px]'>
67+
{FEATURED_TEMPLATES.map((template) => (
68+
<TemplateCard key={template.title} template={template} onSelect={onSelect} />
69+
))}
70+
</div>
71+
72+
{/* Expand / collapse */}
73+
<button
74+
type='button'
75+
onClick={() => setExpanded((prev) => !prev)}
76+
aria-expanded={expanded}
77+
className='flex items-center justify-center gap-[6px] text-[13px] text-[var(--text-secondary)] transition-colors hover:text-[var(--text-body)]'
78+
>
79+
{expanded ? (
80+
<>
81+
Show less <ChevronDown className='h-[14px] w-[14px] rotate-180' />
82+
</>
83+
) : (
84+
<>
85+
More examples <ChevronDown className='h-[14px] w-[14px]' />
86+
</>
87+
)}
88+
</button>
89+
90+
{/* Categorized extras */}
91+
{expanded && (
92+
<div className='flex flex-col gap-[32px]'>
93+
{GROUPED_EXTRAS.map((group) => (
94+
<div key={group.category} className='flex flex-col gap-[12px]'>
95+
<h3 className='font-medium text-[13px] text-[var(--text-secondary)]'>
96+
{group.label}
97+
</h3>
98+
<div className='grid grid-cols-3 gap-[16px]'>
99+
{group.templates.map((template) => (
100+
<TemplateCard key={template.title} template={template} onSelect={onSelect} />
101+
))}
89102
</div>
90103
</div>
91-
</button>
92-
)
93-
})}
104+
))}
105+
</div>
106+
)}
94107
</div>
95108
)
96109
}
110+
111+
interface TemplateCardProps {
112+
template: (typeof TEMPLATES)[number]
113+
onSelect: (prompt: string) => void
114+
}
115+
116+
function TemplateCard({ template, onSelect }: TemplateCardProps) {
117+
const Icon = template.icon
118+
119+
return (
120+
<button
121+
type='button'
122+
onClick={() => onSelect(template.prompt)}
123+
aria-label={`Select template: ${template.title}`}
124+
className='group flex cursor-pointer flex-col text-left'
125+
>
126+
<div className='overflow-hidden rounded-[10px] border border-[var(--border-1)]'>
127+
<div className='relative h-[120px] w-full overflow-hidden'>
128+
{template.image ? (
129+
<Image
130+
src={template.image}
131+
alt={template.title}
132+
fill
133+
unoptimized
134+
className='object-cover transition-transform duration-300 group-hover:scale-105'
135+
/>
136+
) : (
137+
<div className='flex h-full w-full items-center justify-center bg-[var(--surface-3)] transition-colors group-hover:bg-[var(--surface-4)]'>
138+
<Icon className='h-[32px] w-[32px] text-[var(--text-icon)] opacity-40' />
139+
</div>
140+
)}
141+
</div>
142+
<div className='flex flex-col gap-[4px] border-[var(--border-1)] border-t bg-[var(--white)] px-[10px] py-[6px] dark:bg-[var(--surface-4)]'>
143+
<div className='flex items-center gap-[6px]'>
144+
<Icon className='h-[14px] w-[14px] shrink-0 text-[var(--text-icon)]' />
145+
<span className='font-base text-[14px] text-[var(--text-body)]'>{template.title}</span>
146+
</div>
147+
<ModulePills modules={template.modules} />
148+
</div>
149+
</div>
150+
</button>
151+
)
152+
}

apps/sim/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@
144144
"posthog-js": "1.334.1",
145145
"posthog-node": "5.9.2",
146146
"prismjs": "^1.30.0",
147-
"react": "19.2.1",
148-
"react-dom": "19.2.1",
147+
"react": "19.2.4",
148+
"react-dom": "19.2.4",
149149
"react-hook-form": "^7.54.2",
150150
"react-markdown": "^10.1.0",
151151
"react-simple-code-editor": "^0.14.1",

bun.lock

Lines changed: 9 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
"release": "bun run scripts/create-single-release.ts"
2727
},
2828
"overrides": {
29-
"react": "19.2.1",
30-
"react-dom": "19.2.1",
29+
"react": "19.2.4",
30+
"react-dom": "19.2.4",
3131
"next": "16.1.6",
3232
"@next/env": "16.1.6",
3333
"drizzle-orm": "^0.44.5",

0 commit comments

Comments
 (0)