Docs: recipe landing page (#3122)

This commit is contained in:
Rizel Scarlett
2025-06-28 00:00:06 -04:00
committed by GitHub
parent d7fa8aed5c
commit 7899cd0c02
12 changed files with 231 additions and 27 deletions
@@ -0,0 +1,30 @@
import React from 'react';
import Link from '@docusaurus/Link';
import styles from './styles.module.css';
interface CardProps {
title: string;
description: string;
link: string;
icon?: string;
}
export default function Card({ title, description, link, icon }: CardProps): JSX.Element {
const isInternalLink = link.startsWith('/');
const CardWrapper = isInternalLink ? Link : 'a';
const wrapperProps = isInternalLink ? { to: link } : { href: link };
return (
<CardWrapper {...wrapperProps} className={styles.card}>
<div className={styles.cardContent}>
{icon && (
<div className={styles.iconWrapper}>
<img src={icon} alt="" className={styles.icon} />
</div>
)}
<h3 className={styles.cardTitle}>{title}</h3>
<p className={styles.cardDescription}>{description}</p>
</div>
</CardWrapper>
);
}
@@ -0,0 +1,79 @@
.categorySection {
margin: 3rem 0;
}
.categoryTitle {
font-size: 1.5rem;
margin-bottom: 1.5rem;
color: var(--ifm-heading-color);
font-weight: 600;
}
.cardGrid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
margin: 1rem 0;
}
.singleCardGrid {
display: grid;
grid-template-columns: minmax(300px, 600px);
gap: 1.5rem;
margin: 1rem 0;
}
.pageTitle {
font-size: 2.5rem;
margin-bottom: 1rem;
color: var(--ifm-heading-color);
}
.pageDescription {
font-size: 1.2rem;
color: var(--ifm-color-emphasis-700);
margin-bottom: 2rem;
line-height: 1.6;
}
/* Video container styles */
:global(.video-container) {
position: relative;
width: 100%;
max-width: 800px;
margin: 0 auto 3rem;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 12px -6px rgba(0, 0, 0, 0.1);
}
/* Card styles */
.card {
display: block;
padding: 1.75rem;
border-radius: 12px;
background: transparent;
border: 1px solid var(--ifm-color-emphasis-200);
transition: border-color 0.2s ease, box-shadow 0.2s ease;
text-decoration: none !important;
color: inherit !important;
}
.card:hover {
border-color: var(--ifm-color-emphasis-500);
box-shadow: 0 4px 12px -6px rgba(0, 0, 0, 0.1);
text-decoration: none;
}
.cardTitle {
font-size: 1.4rem;
margin: 0 0 0.75rem 0;
color: var(--ifm-heading-color);
font-weight: 600;
}
.cardDescription {
margin: 0;
color: var(--ifm-color-emphasis-700);
line-height: 1.6;
}
+20 -15
View File
@@ -12,7 +12,7 @@ export default function RecipeGenerator() {
const [activities, setActivities] = useState([]);
const [newActivity, setNewActivity] = useState('');
const [copied, setCopied] = useState(false);
const [errors, setErrors] = useState({});
const [errors, setErrors] = useState<{[key: string]: string}>({});
const [outputFormat, setOutputFormat] = useState('url'); // 'url' or 'yaml'
const [authorContact, setAuthorContact] = useState('');
const [extensionsList, setExtensionsList] = useState([
@@ -59,7 +59,7 @@ export default function RecipeGenerator() {
// Form validation
const validateForm = useCallback(() => {
const newErrors = {};
const newErrors: {[key: string]: string} = {};
if (!title.trim()) {
newErrors.title = 'Title is required';
@@ -89,6 +89,7 @@ export default function RecipeGenerator() {
title,
description,
instructions,
prompt: prompt.trim() || undefined,
activities: activities.length > 0 ? activities : undefined
};
@@ -272,6 +273,23 @@ instructions: ${instructions}
{errors.instructions && <div className="text-red-500 text-sm mt-1">{errors.instructions}</div>}
</div>
{/* Initial Prompt */}
<div>
<label htmlFor="prompt" className="block text-sm font-medium text-textStandard mb-2">
Initial Prompt (optional)
</label>
<textarea
id="prompt"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
className="w-full p-3 border border-borderSubtle rounded-lg bg-bgSubtle text-textStandard min-h-[100px]"
placeholder="Enter an initial prompt to start the conversation (optional)"
/>
<div className="text-sm text-textSubtle mt-1">
If provided, this message will automatically start the conversation when the recipe is launched.
</div>
</div>
{/* YAML-specific fields */}
{outputFormat === 'yaml' && (
<>
@@ -289,19 +307,6 @@ instructions: ${instructions}
/>
</div>
<div>
<label htmlFor="prompt" className="block text-sm font-medium text-textStandard mb-2">
Initial Prompt (optional)
</label>
<textarea
id="prompt"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
className="w-full p-3 border border-borderSubtle rounded-lg bg-bgSubtle text-textStandard min-h-[100px]"
placeholder="Enter an initial prompt for the recipe"
/>
</div>
<div>
<label className="block text-sm font-medium text-textStandard mb-2">
Extensions (optional)
+1 -1
View File
@@ -106,7 +106,7 @@ export default function RecipePage() {
</div>
<p className="text-textProminent">
Save time and skip setup launch any{" "}
<Link to="/docs/guides/session-recipes" className="text-purple-600 hover:underline">
<Link to="/docs/guides/recipes/session-recipes" className="text-purple-600 hover:underline">
Goose agent recipe
</Link>{" "}
shared by the community with a single click.