Skip to content

Commit c03d524

Browse files
feat: update iframe capabilities for dojo (re CPK docs) (#523)
* Add `chatDefaultOpen` parameter to close chat sidebar by default * chore: remove unused imports * feat: pass `chatDefaultOpen` to all uses of `CopilotSidebar` in Dojo No instances of `CopilotPopup` are currently being used, and `CopilotChat` does not support `defaultOpen` prop * fix: hide mobile header when `sidebarHidden=true` (`sidebar=false`) * chore: consolidate redundant base styles * fix: enforce body background/foreground colors (currently broken on 404) * fix: support dark mode on code tabs * chore: untrack and remove .DS_Store * feat: improve dark mode styles * feat: allow overriding theme via url `theme` param * fix: match background to chat background color * feat: finesse iframe'd styling for dojo examples * fix: remove content rounded corners when used in iframe * fix: use `neutral` color instead of `gray` when in iframe * feat: add light and dark mode support for Monaco code editor * feat: remove shadow from active tab in code editor tabs * fix: use copilotkit docs bg color for code editor on dark mode * feat: lighten code tabs active tab on light mode * feat: offset tabs bg-color on dark mode * feat: offset tabs bg-color on dark mode from 10% to 5% * feat: round corners on code viewer contents to show as visually nested * feat: refine how we mix background color * feat: change bg mix opacity from 10% to 8% for light mode * feat: change bg mix opacity from 8% to 3% for light mode * fix(code-viewer): remove bottom border * feat(code-viewer): refine CodeEditor wrapper border color * fix(code-viewer): collapse redundant x-axis borders * feat(code-viewer): refine border colors * feat: add hook check for if the dojo is iframed from cpk docs * fix: dojo sidebar collapsing, add theme color when in cpk iframe * feat: remove override forcing primary color * fix: don't round corners on FileTree, even when in iframe * fix: fix e2e test error * chore: update files.json
1 parent a9398d1 commit c03d524

File tree

19 files changed

+273
-88
lines changed

19 files changed

+273
-88
lines changed

typescript-sdk/apps/dojo/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"start": "npm run generate-content-json && next start",
99
"lint": "next lint",
1010
"mastra:dev": "mastra dev",
11-
"generate-content-json": "npx tsx scripts/generate-content-json.ts"
11+
"generate-content-json": "npx tsx scripts/generate-content-json.ts",
12+
"run-everything": "./scripts/prep-dojo-everything.js && ./scripts/run-dojo-everything.js"
1213
},
1314
"dependencies": {
1415
"@ag-ui/a2a-middleware": "workspace:*",

typescript-sdk/apps/dojo/src/app/[integrationId]/feature/layout.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import filesJSON from '../../../files.json'
66
import Readme from "@/components/readme/readme";
77
import CodeViewer from "@/components/code-viewer/code-viewer";
88
import { useURLParams } from "@/contexts/url-params-context";
9+
import { cn } from "@/lib/utils";
910

1011
type FileItem = {
1112
name: string;
@@ -24,6 +25,7 @@ interface Props {
2425
}
2526

2627
export default function FeatureLayout({ children, params }: Props) {
28+
const { sidebarHidden } = useURLParams();
2729
const { integrationId } = React.use(params);
2830
const pathname = usePathname();
2931
const { view } = useURLParams();
@@ -58,7 +60,13 @@ export default function FeatureLayout({ children, params }: Props) {
5860
}, [children, codeFiles, readme, view])
5961

6062
return (
61-
<div className="bg-white rounded-lg w-full h-full overflow-hidden">
63+
<div className={cn(
64+
"bg-white w-full h-full overflow-hidden",
65+
// if used in iframe, match background to chat background color, otherwise, use white
66+
sidebarHidden && "bg-(--copilot-kit-background-color)",
67+
// if not used in iframe, round the corners of the content area
68+
!sidebarHidden && "rounded-lg",
69+
)}>
6270
<div className="flex flex-col h-full overflow-auto">
6371
{content}
6472
</div>

typescript-sdk/apps/dojo/src/app/[integrationId]/feature/predictive_state_updates/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { CopilotKit, useCoAgent, useCopilotAction, useCopilotChat } from "@copil
1313
import { CopilotChat, CopilotSidebar } from "@copilotkit/react-ui";
1414
import { useMobileView } from "@/utils/use-mobile-view";
1515
import { useMobileChat } from "@/utils/use-mobile-chat";
16+
import { useURLParams } from "@/contexts/url-params-context";
1617

1718
const extensions = [StarterKit];
1819

@@ -25,6 +26,7 @@ interface PredictiveStateUpdatesProps {
2526
export default function PredictiveStateUpdates({ params }: PredictiveStateUpdatesProps) {
2627
const { integrationId } = React.use(params);
2728
const { isMobile } = useMobileView();
29+
const { chatDefaultOpen } = useURLParams();
2830
const defaultChatHeight = 50;
2931
const { isChatOpen, setChatHeight, setIsChatOpen, isDragging, chatHeight, handleDragStart } =
3032
useMobileChat(defaultChatHeight);
@@ -162,7 +164,7 @@ export default function PredictiveStateUpdates({ params }: PredictiveStateUpdate
162164
</>
163165
) : (
164166
<CopilotSidebar
165-
defaultOpen={true}
167+
defaultOpen={chatDefaultOpen}
166168
suggestions={[
167169
{
168170
title: "Write a pirate story",

typescript-sdk/apps/dojo/src/app/[integrationId]/feature/shared_state/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import "@copilotkit/react-ui/styles.css";
77
import "./style.css";
88
import { useMobileView } from "@/utils/use-mobile-view";
99
import { useMobileChat } from "@/utils/use-mobile-chat";
10+
import { useURLParams } from "@/contexts/url-params-context";
1011

1112
interface SharedStateProps {
1213
params: Promise<{
@@ -17,6 +18,7 @@ interface SharedStateProps {
1718
export default function SharedState({ params }: SharedStateProps) {
1819
const { integrationId } = React.use(params);
1920
const { isMobile } = useMobileView();
21+
const { chatDefaultOpen } = useURLParams();
2022
const defaultChatHeight = 50;
2123
const { isChatOpen, setChatHeight, setIsChatOpen, isDragging, chatHeight, handleDragStart } =
2224
useMobileChat(defaultChatHeight);
@@ -137,7 +139,7 @@ export default function SharedState({ params }: SharedStateProps) {
137139
</>
138140
) : (
139141
<CopilotSidebar
140-
defaultOpen={true}
142+
defaultOpen={chatDefaultOpen}
141143
labels={{
142144
title: chatTitle,
143145
initial: initialLabel,

typescript-sdk/apps/dojo/src/app/[integrationId]/feature/subgraphs/page.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { CopilotKit, useCoAgent, useLangGraphInterrupt } from "@copilotkit/react
66
import { CopilotSidebar } from "@copilotkit/react-ui";
77
import { useMobileView } from "@/utils/use-mobile-view";
88
import { useMobileChat } from "@/utils/use-mobile-chat";
9+
import { useURLParams } from "@/contexts/url-params-context";
910

1011
interface SubgraphsProps {
1112
params: Promise<{
@@ -152,6 +153,7 @@ function InterruptHumanInTheLoop<TAgent extends AvailableAgents>({
152153
export default function Subgraphs({ params }: SubgraphsProps) {
153154
const { integrationId } = React.use(params);
154155
const { isMobile } = useMobileView();
156+
const { chatDefaultOpen } = useURLParams();
155157
const defaultChatHeight = 50;
156158
const {
157159
isChatOpen,
@@ -240,7 +242,7 @@ export default function Subgraphs({ params }: SubgraphsProps) {
240242
{/* Chat Content */}
241243
<div className="flex-1 flex flex-col min-h-0 overflow-hidden pb-16">
242244
<CopilotSidebar
243-
defaultOpen={true}
245+
defaultOpen={chatDefaultOpen}
244246
labels={{
245247
title: chatTitle,
246248
initial: initialLabel,
@@ -260,7 +262,7 @@ export default function Subgraphs({ params }: SubgraphsProps) {
260262
</>
261263
) : (
262264
<CopilotSidebar
263-
defaultOpen={true}
265+
defaultOpen={chatDefaultOpen}
264266
labels={{
265267
title: chatTitle,
266268
initial: initialLabel,

typescript-sdk/apps/dojo/src/app/[integrationId]/feature/tool_based_generative_ui/page.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
import React, { useState } from "react";
33
import "@copilotkit/react-ui/styles.css";
44
import { CopilotKit, useCopilotAction } from "@copilotkit/react-core";
5-
import { CopilotSidebar, CopilotPopup } from "@copilotkit/react-ui";
5+
import { CopilotSidebar } from "@copilotkit/react-ui";
66
import {
77
Carousel,
88
CarouselContent,
99
CarouselItem,
1010
CarouselNext,
1111
CarouselPrevious,
1212
} from "@/components/ui/carousel";
13+
import { useURLParams } from "@/contexts/url-params-context";
1314

1415
interface ToolBasedGenerativeUIProps {
1516
params: Promise<{
@@ -26,9 +27,10 @@ interface Haiku {
2627

2728
export default function ToolBasedGenerativeUI({ params }: ToolBasedGenerativeUIProps) {
2829
const { integrationId } = React.use(params);
30+
const { chatDefaultOpen } = useURLParams();
2931

3032
const chatProps = {
31-
defaultOpen: true,
33+
defaultOpen: chatDefaultOpen,
3234
labels: {
3335
title: "Haiku Generator",
3436
initial: "I'm a haiku generator 👋. How can I help you?",

typescript-sdk/apps/dojo/src/app/globals.css

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@
186186
--anthropic: hsl(240 80% 60%); /* Bright blue */
187187
--cohere: hsl(0 80% 60%); /* Bright red */ --background: oklch(1 0 0); --foreground: oklch(0.145 0 0);
188188

189+
--cpk-docs-dark-bg: oklch(0.274 0.006 286.033);
190+
--cpk-docs-primary: oklch(0.55 0.25 285);
189191
}
190192

191193
.dark {
@@ -233,15 +235,6 @@
233235
--chart-5: oklch(0.645 0.246 16.439);
234236
}
235237

236-
@layer base {
237-
* {
238-
@apply border-border outline-ring/50;
239-
}
240-
body {
241-
@apply bg-background text-foreground font-sans;
242-
}
243-
}
244-
245238
@theme inline {
246239
--radius-sm: calc(var(--radius) - 4px);
247240
--radius-md: calc(var(--radius) - 2px);
@@ -278,13 +271,82 @@
278271
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
279272
--color-sidebar-border: var(--sidebar-border);
280273
--color-sidebar-ring: var(--sidebar-ring);
274+
--color-cpk-docs-dark-bg: var(--cpk-docs-dark-bg);
275+
--color-cpk-docs-primary: var(--cpk-docs-primary);
276+
277+
/* supporting variables for color-mix (see related color-mix-* utilities below */
278+
--color-mix-from: var(--tw-mix-from);
279+
--color-mix-to: var(--tw-mix-to);
280+
--color-mix: var(--tw-mix);
281281
}
282282

283283
@layer base {
284284
* {
285285
@apply border-border outline-ring/50;
286286
}
287287
body {
288-
@apply bg-background text-foreground;
288+
/*
289+
TODO: remove important modifier (!)
290+
after troubleshooting why the dojo
291+
sidebar text is white when on 404 pages
292+
*/
293+
@apply bg-background! text-foreground! font-sans;
289294
}
290295
}
296+
297+
/* hide scroll decoration on code blocks */
298+
.monaco-editor .overflow-guard .scroll-decoration {
299+
@apply hidden!;
300+
}
301+
302+
@utility mix-from-* {
303+
--tw-mix-from-color: --value(--color-*, color, [color]);
304+
--tw-mix-from-opacity: --modifier(--opacity-*, [percentage]);
305+
--tw-mix-from-opacity: calc(--modifier(number) * 1%);
306+
--tw-mix-from-opacity: calc(--modifier([number]) * 100%);
307+
--tw-mix-from: --alpha(var(--tw-mix-from-color) / var(--tw-mix-from-opacity, 100%));
308+
/* calculate the final color-mix result */
309+
--tw-mix: color-mix(color-mix(in srgb, var(--color-mix-from), var(--color-mix-to) var(--tw-mix-percent, 50%)) var(--tw-mix-opacity, 100%), transparent);
310+
@supports (color: color-mix(in lab, red, red)) {
311+
--tw-mix: color-mix(color-mix(in oklab, var(--color-mix-from), var(--color-mix-to) var(--tw-mix-percent, 50%)) var(--tw-mix-opacity, 100%), transparent);
312+
}
313+
/* redefining the color variables here to ensure they receive the latest values */
314+
--color-mix-from: var(--tw-mix-from);
315+
--color-mix-to: var(--tw-mix-to);
316+
--color-mix: var(--tw-mix);
317+
}
318+
319+
@utility mix-to-* {
320+
--tw-mix-to-color: --value(--color-*, color, [color]);
321+
--tw-mix-to-opacity: --modifier(--opacity-*, [percentage]);
322+
--tw-mix-to-opacity: calc(--modifier(number) * 1%);
323+
--tw-mix-to-opacity: calc(--modifier([number]) * 100%);
324+
--tw-mix-to: --alpha(var(--tw-mix-to-color) / var(--tw-mix-to-opacity, 100%));
325+
/* calculate the final color-mix result */
326+
--tw-mix: color-mix(color-mix(in srgb, var(--color-mix-from), var(--color-mix-to) var(--tw-mix-percent, 50%)) var(--tw-mix-opacity, 100%), transparent);
327+
@supports (color: color-mix(in lab, red, red)) {
328+
--tw-mix: color-mix(color-mix(in oklab, var(--color-mix-from), var(--color-mix-to) var(--tw-mix-percent, 50%)) var(--tw-mix-opacity, 100%), transparent);
329+
}
330+
/* redefining the color variables here to ensure they receive the latest values */
331+
--color-mix-from: var(--tw-mix-from);
332+
--color-mix-to: var(--tw-mix-to);
333+
--color-mix: var(--tw-mix);
334+
}
335+
336+
@utility mix-* {
337+
--tw-mix-percent: --value(--opacity-*, [percentage]);
338+
--tw-mix-percent: calc(--value(number) * 1%);
339+
--tw-mix-percent: calc(--value([number]) * 100%);
340+
--tw-mix-opacity: --modifier(--opacity-*, [percentage]);
341+
--tw-mix-opacity: calc(--modifier(number) * 1%);
342+
--tw-mix-opacity: calc(--modifier([number]) * 100%);
343+
/* calculate the final color-mix result */
344+
--tw-mix: color-mix(in srgb, color-mix(in srgb, var(--color-mix-from), var(--color-mix-to) var(--tw-mix-percent, 50%)) var(--tw-mix-opacity, 100%), transparent);
345+
@supports (color: color-mix(in lab, red, red)) {
346+
--tw-mix: color-mix(in oklab, color-mix(in oklab, var(--color-mix-from), var(--color-mix-to) var(--tw-mix-percent, 50%)) var(--tw-mix-opacity, 100%), transparent);
347+
}
348+
/* redefining the color variables here to ensure they receive the latest values */
349+
--color-mix-from: var(--tw-mix-from);
350+
--color-mix-to: var(--tw-mix-to);
351+
--color-mix: var(--tw-mix);
352+
}

typescript-sdk/apps/dojo/src/app/layout.tsx

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
33
import { Geist, Geist_Mono } from "next/font/google";
44
import "./globals.css";
55
import "@copilotkit/react-ui/styles.css";
6-
import { ThemeProvider } from "@/components/theme-provider";
6+
import { ThemeWrapper } from "@/components/theme-wrapper";
77
import { MainLayout } from "@/components/layout/main-layout";
88
import { URLParamsProvider } from "@/contexts/url-params-context";
99

@@ -30,19 +30,13 @@ export default function RootLayout({
3030
return (
3131
<html lang="en" suppressHydrationWarning>
3232
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
33-
<ThemeProvider
34-
attribute="class"
35-
defaultTheme="light"
36-
enableSystem={false}
37-
themes={['light']}
38-
disableTransitionOnChange
39-
>
40-
<Suspense>
41-
<URLParamsProvider>
33+
<Suspense>
34+
<URLParamsProvider>
35+
<ThemeWrapper>
4236
<MainLayout>{children}</MainLayout>
43-
</URLParamsProvider>
44-
</Suspense>
45-
</ThemeProvider>
37+
</ThemeWrapper>
38+
</URLParamsProvider>
39+
</Suspense>
4640
</body>
4741
</html>
4842
);

typescript-sdk/apps/dojo/src/components/code-viewer/code-editor.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ export function CodeEditor({ file, onFileChange }: CodeEditorProps) {
1414
}
1515
};
1616

17-
const theme = useTheme();
17+
const { forcedTheme, resolvedTheme } = useTheme();
18+
const currentTheme = forcedTheme || resolvedTheme;
1819

1920
if (file?.language === "ts") file.language = "typescript";
2021

@@ -36,7 +37,7 @@ export function CodeEditor({ file, onFileChange }: CodeEditorProps) {
3637
enabled: false,
3738
},
3839
}}
39-
theme="vs-dark"
40+
theme={currentTheme !== "dark" ? "light" : "vs-dark"}
4041
/>
4142
</div>
4243
) : (

0 commit comments

Comments
 (0)