Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,16 @@ Consult these guides before working on related tasks:
- Detail pages render the imported workflow and agent topology. Gallery cards
instead show a fixed asset inventory for workflows, agents, tools, MCP
servers, and skills so dense graphs are not compressed into unreadable
thumbnails.
thumbnails. Detail pages also use that inventory on phones; their interactive
graphs start at the 640px breakpoint, with compact agent and workflow lists
preserving the underlying information on smaller screens.
- The browser receives compact allowlisted graph data. Raw schemas, icons,
environment connection identifiers, and source blobs stay out of generated
content.
- Download ZIPs are deterministic rebuilds of the `solution/` contents at archive
root; gallery sidecars are excluded. Downloads stay locked until the visitor
acknowledges that community solutions should be reviewed and imported only
from a trusted source.
- Shared links use the official Copilot Studio mark and the gallery's five asset
types in a dedicated 1200x630 social image. Keep Open Graph and X/Twitter
metadata aligned when changing the site's sharing identity.
Binary file added public/copilot-studio-gallery-social.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 21 additions & 2 deletions src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@ import { withBase } from "../lib/url";
interface Props {
title?: string;
description?: string;
socialTitle?: string;
}

const {
title = "Copilot Studio Gallery",
description = "Discover community-built Copilot Studio solutions through their agents and workflow canvases.",
socialTitle,
} = Astro.props;
const fullTitle =
title === "Copilot Studio Gallery"
? title
: `${title} · Copilot Studio Gallery`;
const shareTitle = socialTitle ?? fullTitle;
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
const socialImageUrl = new URL(withBase("/copilot-studio-gallery-social.png"), Astro.site);
const socialImageAlt = "Copilot Studio Gallery with workflow, agent, tool, MCP, and skill symbols.";
---

<!doctype html>
Expand All @@ -33,11 +39,24 @@ const fullTitle =
<meta name="generator" content={Astro.generator} />
<title>{fullTitle}</title>
<meta name="description" content={description} />
<meta property="og:title" content={fullTitle} />
<link rel="canonical" href={canonicalUrl} />
<meta property="og:title" content={shareTitle} />
<meta property="og:description" content={description} />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Copilot Studio Gallery" />
<link rel="icon" type="image/svg+xml" href={withBase("/copilot-studio.svg")} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:image" content={socialImageUrl} />
<meta property="og:image:secure_url" content={socialImageUrl} />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content={socialImageAlt} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={shareTitle} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={socialImageUrl} />
<meta name="twitter:image:alt" content={socialImageAlt} />
<link rel="icon" type="image/svg+xml" href={withBase("/favicon.svg")} />
</head>
<body class="flex min-h-screen flex-col antialiased">
<header class="sticky top-0 z-40 border-b border-border bg-surface/95 backdrop-blur-xl">
Expand Down
2 changes: 1 addition & 1 deletion src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const contributors = collectContributors(solutions);
const featuredSolutions = solutions.filter((solution) => solution.data.featured);
---

<Layout>
<Layout socialTitle="Copilot Studio Gallery — Community Agents & Workflows">
<section class="studio-canvas border-b border-border">
<div class="mx-auto w-full max-w-gallery px-4 py-10 sm:px-6 sm:py-12">
<div class="mx-auto max-w-4xl text-center">
Expand Down
48 changes: 38 additions & 10 deletions src/pages/solutions/[slug].astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
import { getCollection, render } from "astro:content";
import Layout from "../../layouts/Layout.astro";
import AssetSummaryPreview from "../../components/AssetSummaryPreview.astro";
import GraphCanvas from "../../components/graph/GraphCanvas";
import WorkflowExplorer from "../../components/graph/WorkflowExplorer";
import { authorKey, solutionMakeup } from "../../lib/schema";
Expand Down Expand Up @@ -49,13 +50,23 @@ const heroGraph = data.workflows[0]?.graph ?? data.agentGraph;
</div>
</div>
<div class="solution-hero-preview relative overflow-hidden border-t border-border bg-elevated text-muted">
<GraphCanvas
graph={heroGraph}
label={`${data.name} topology preview`}
variant={data.workflows.length ? "workflow" : "agent"}
compact
client:load
/>
<div class="h-32 px-4 sm:hidden">
<AssetSummaryPreview
agentCount={data.agentCount}
workflowCount={data.workflowCount}
agentGraph={data.agentGraph}
label={`${data.name} assets`}
/>
</div>
<div class="hidden sm:block">
<GraphCanvas
graph={heroGraph}
label={`${data.name} topology preview`}
variant={data.workflows.length ? "workflow" : "agent"}
compact
client:media="(min-width: 640px)"
/>
</div>
</div>
<div class="grid gap-px border-t border-border bg-border sm:grid-cols-4">
<div class="bg-surface px-5 py-4"><p class="font-mono text-[10px] uppercase tracking-[0.12em] text-soft">Agents</p><p class="mt-1 text-xl font-semibold text-ink">{data.agentCount}</p></div>
Expand Down Expand Up @@ -98,8 +109,8 @@ const heroGraph = data.workflows[0]?.graph ?? data.agentGraph;
<h2 class="text-xl font-semibold text-ink">Agent architecture</h2>
<p class="mt-1 text-sm text-muted">Select an agent, tool, or skill to inspect the published configuration.</p>
</div>
<div class="overflow-hidden rounded-2xl border border-border bg-elevated card-shadow">
<GraphCanvas graph={data.agentGraph} label={`${data.name} agent architecture`} variant="agent" client:load />
<div class="hidden overflow-hidden rounded-2xl border border-border bg-elevated card-shadow sm:block">
<GraphCanvas graph={data.agentGraph} label={`${data.name} agent architecture`} variant="agent" client:media="(min-width: 640px)" />
</div>
<div class="mt-5 grid gap-3 md:grid-cols-2">
{data.agents.map((agent) => (
Expand Down Expand Up @@ -127,7 +138,24 @@ const heroGraph = data.workflows[0]?.graph ?? data.agentGraph;
<h2 class="text-xl font-semibold text-ink">Workflow canvases</h2>
<p class="mt-1 text-sm text-muted">These positions and connections come from the saved designer graph in the exported solution.</p>
</div>
<WorkflowExplorer workflows={data.workflows} client:load />
<div class="grid gap-3 sm:hidden">
{
data.workflows.map((workflow) => (
<article class="rounded-2xl border border-border bg-surface p-4 card-shadow">
<p class="font-mono text-[10px] uppercase tracking-[0.12em] text-soft">{workflow.id}</p>
<h3 class="mt-1 font-semibold text-ink">{workflow.name}</h3>
<div class="mt-3 flex flex-wrap gap-3 text-xs text-muted">
{workflow.trigger && <span>Trigger: {workflow.trigger}</span>}
<span>{workflow.nodeCount} steps</span>
<span>{workflow.edgeCount} connections</span>
</div>
</article>
))
}
</div>
<div class="hidden sm:block">
<WorkflowExplorer workflows={data.workflows} client:media="(min-width: 640px)" />
</div>
</section>

<section id="panel-files" role="tabpanel" data-panel="files" class="hidden pt-7">
Expand Down
Loading