Skip to content

Commit bb833fa

Browse files
authored
[shared-ui] Update default app theme (#5639)
1 parent c737a80 commit bb833fa

File tree

17 files changed

+81
-26
lines changed

17 files changed

+81
-26
lines changed

.changeset/pretty-wolves-enter.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@breadboard-ai/unified-server": patch
3+
"@breadboard-ai/visual-editor": patch
4+
"@google-labs/breadboard": patch
5+
"@breadboard-ai/shared-ui": patch
6+
"@google-labs/breadboard-schema": patch
7+
"@breadboard-ai/types": patch
8+
---
9+
10+
Update default app theme

packages/board-server/src/server/storage-providers/inmemory.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ suite("In-memory storage provider", () => {
4242
tags: [],
4343
thumbnail: "",
4444
graph: {
45-
description: "",
45+
description: "Add a description",
4646
edges: [],
4747
nodes: [],
4848
title: "Untitled Flow",
@@ -75,8 +75,8 @@ suite("In-memory storage provider", () => {
7575

7676
test("upsert board", async () => {
7777
const board: StorageBoard = {
78-
name: '', // Explicitly no name - new board.
79-
owner: '',
78+
name: "", // Explicitly no name - new board.
79+
owner: "",
8080
displayName: "Test Board",
8181
description: "Board For Testing",
8282
tags: ["published"],
@@ -88,7 +88,7 @@ suite("In-memory storage provider", () => {
8888
assert.notEqual(created.name, ""); // The result must have a name assigned.
8989
board.name = created.name;
9090
assert.deepEqual(created, board);
91-
board.description = 'updated';
91+
board.description = "updated";
9292
const updated = await provider.upsertBoard(board);
9393
assert.deepEqual(updated, board);
9494
});

packages/board-server/src/server/storage-providers/inmemory.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export class InMemoryStorageProvider implements BoardServerStore {
4242
async createBoard(userId: string, name: string): Promise<void> {
4343
this.#boards[name] = {
4444
name,
45-
owner: userId,
45+
owner: userId,
4646
displayName: name,
4747
description: "",
4848
tags: [],
@@ -56,7 +56,10 @@ export class InMemoryStorageProvider implements BoardServerStore {
5656
}
5757

5858
async upsertBoard(board: Readonly<StorageBoard>): Promise<StorageBoard> {
59-
const updatedBoard: StorageBoard = {...board, name: board.name || crypto.randomUUID()};
59+
const updatedBoard: StorageBoard = {
60+
...board,
61+
name: board.name || crypto.randomUUID(),
62+
};
6063
this.#boards[updatedBoard.name] = updatedBoard;
6164
return updatedBoard;
6265
}

packages/breadboard/src/editor/blank.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ const llmContentConfig = (type: string) => ({
2828

2929
const BLANK_GRAPH: GraphDescriptor = {
3030
title: "Untitled Flow",
31-
description: "",
31+
description: "Add a description",
3232
version: "0.0.1",
3333
nodes: [],
3434
edges: [],
3535
};
3636

3737
const BLANK_LLM_CONTENT_GRAPH: GraphDescriptor = {
3838
title: "Untitled Flow",
39-
description: "",
39+
description: "Add a description",
4040
version: "0.0.1",
4141
nodes: [
4242
{ type: "input", id: "input", configuration: llmContentConfig("input") },

packages/manifest/bbm.schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,9 @@
639639
"GraphTheme": {
640640
"additionalProperties": false,
641641
"properties": {
642+
"isDefaultTheme": {
643+
"type": "boolean"
644+
},
642645
"splashScreen": {
643646
"$ref": "#/definitions/StoredDataCapabilityPart"
644647
},

packages/schema/breadboard.schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,9 @@
570570
},
571571
"splashScreen": {
572572
"$ref": "#/definitions/StoredDataCapabilityPart"
573+
},
574+
"isDefaultTheme": {
575+
"type": "boolean"
573576
}
574577
},
575578
"additionalProperties": false

packages/shared-ui/src/app-templates/basic/index.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,10 @@ export class Template extends LitElement implements AppTemplate {
272272
273273
&::before {
274274
content: "";
275-
width: 100%;
275+
width: var(--splash-width, 100%);
276276
flex: 1;
277-
background: var(--splash-image, url(/images/app/generic-flow.jpg))
278-
center center / cover no-repeat;
277+
background: var(--splash-image, var(--bb-logo)) center center /
278+
var(--splash-fill, cover) no-repeat;
279279
mask-image: linear-gradient(
280280
to bottom,
281281
rgba(255, 0, 255, 1) 0%,
@@ -289,8 +289,8 @@ export class Template extends LitElement implements AppTemplate {
289289
& h1 {
290290
background: var(--background-color, none);
291291
border-radius: var(--bb-grid-size-2);
292-
font: 500 var(--font-style) 32px / 42px var(--font-family);
293-
color: var(--primary-color, var(--bb-neutral-700));
292+
font: 400 var(--font-style) 32px / 42px var(--font-family);
293+
color: var(--text-color, var(--bb-neutral-700));
294294
margin: 0 0 var(--bb-grid-size-3);
295295
flex: 0 0 auto;
296296
max-width: 80%;
@@ -568,7 +568,8 @@ export class Template extends LitElement implements AppTemplate {
568568
var(--bb-icon-generative) 12px center / 16px 16px no-repeat;
569569
color: var(--primary-text-color, var(--bb-ui-700));
570570
border-radius: 20px;
571-
border: 1px solid var(--primary-color, var(--bb-ui-100));
571+
border: 1px solid
572+
var(--start-border, var(--primary-color, var(--bb-ui-100)));
572573
font: 400 var(--bb-label-large) /
573574
var(--bb-label-line-height-large) var(--bb-font-family);
574575
padding: 0 var(--bb-grid-size-5) 0 var(--bb-grid-size-9);
@@ -1339,6 +1340,14 @@ export class Template extends LitElement implements AppTemplate {
13391340
}
13401341

13411342
if (typeof this.options.splashImage === "string") {
1343+
// Special-case the default theme based on the mime types.
1344+
// TODO: Replace this with a more robust check.
1345+
if (this.options.isDefaultTheme) {
1346+
styles["--splash-width"] = "50%";
1347+
styles["--splash-fill"] = "contain";
1348+
styles["--start-border"] = "var(--secondary-color)";
1349+
}
1350+
13421351
styles["--splash-image"] = this.options.splashImage;
13431352
}
13441353

packages/shared-ui/src/elements/app-preview/app-preview.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,13 @@ import {
2828
STATUS,
2929
TopGraphRunResult,
3030
} from "../../types/types.js";
31-
import { getGlobalColor } from "../../utils/color.js";
3231
import { classMap } from "lit/directives/class-map.js";
3332

34-
const primaryColor = getGlobalColor("--bb-ui-700");
35-
const secondaryColor = getGlobalColor("--bb-ui-400");
36-
const backgroundColor = getGlobalColor("--bb-neutral-0");
37-
const textColor = getGlobalColor("--bb-neutral-900");
38-
const primaryTextColor = getGlobalColor("--bb-neutral-0");
33+
const primaryColor = "#ffffff";
34+
const secondaryColor = "#7a7a7a";
35+
const backgroundColor = "#ffffff";
36+
const textColor = "#1a1a1a";
37+
const primaryTextColor = "#1a1a1a";
3938

4039
/**
4140
* Based on https://www.w3.org/TR/AERT/#color-contrast
@@ -164,6 +163,7 @@ export class AppPreview extends LitElement {
164163
const { themes, theme } = this.graph.metadata.visual.presentation;
165164
if (themes[theme]) {
166165
templateAdditionalOptions = themes[theme].templateAdditionalOptions;
166+
options.isDefaultTheme = themes[theme].isDefaultTheme;
167167
}
168168
} else if (
169169
this.graph?.metadata?.visual?.presentation?.templateAdditionalOptions

packages/shared-ui/src/elements/app-preview/app-theme-creator.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ export class AppThemeCreator extends LitElement {
251251
background: url(/images/progress-ui.svg) center center / 20px
252252
20px no-repeat;
253253
border-radius: var(--bb-grid-size-2) var(--bb-grid-size-2) 0 0;
254+
255+
&.default {
256+
object-fit: contain;
257+
}
254258
}
255259
256260
& .color {
@@ -661,6 +665,9 @@ export class AppThemeCreator extends LitElement {
661665
<img
662666
src=${url ?? "/images/app/generic-flow.jpg"}
663667
alt="Theme thumbnail"
668+
class=${classMap({
669+
default: theme.isDefaultTheme ?? false,
670+
})}
664671
/>
665672
<span
666673
class="color"

packages/shared-ui/src/elements/welcome-panel/gallery.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ export class Gallery extends LitElement {
9797
border-bottom: var(--border);
9898
/* Matches the color of the placeholder background */
9999
background-color: #ebf5ff;
100+
101+
&.default {
102+
background-color: var(--bb-neutral-0);
103+
object-fit: contain;
104+
box-sizing: border-box;
105+
padding: var(--bb-grid-size-8);
106+
}
100107
}
101108
102109
.details {
@@ -367,6 +374,9 @@ export class Gallery extends LitElement {
367374

368375
#renderBoard([name, item]: [string, GraphProviderItem]) {
369376
const { url, mine, title, description, thumbnail } = item;
377+
// TODO: Replace this with a more robust check. The theme does include this
378+
// information but the board server logic doesn't currently expose it.
379+
const isDefaultTheme = thumbnail?.startsWith("data:") ?? false;
370380
return html`
371381
<div
372382
aria-role="button"
@@ -378,7 +388,7 @@ export class Gallery extends LitElement {
378388
${keyed(
379389
thumbnail,
380390
html`<img
381-
class="thumbnail"
391+
class=${classMap({ thumbnail: true, default: isDefaultTheme })}
382392
src=${thumbnail ?? "/images/placeholder.svg"}
383393
/>`
384394
)}

packages/shared-ui/src/types/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ export interface AppTemplateOptions {
557557
description?: string | null;
558558
mode: "light" | "dark";
559559
theme?: AppThemeColors;
560+
isDefaultTheme?: boolean;
560561
splashImage: string | boolean;
561562
additionalOptions?: AppTemplateAdditionalOptionsChosen;
562563
}

packages/types/src/graph-descriptor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ export type GraphTheme = {
357357
template?: string;
358358
templateAdditionalOptions?: Record<string, string>;
359359
splashScreen?: StoredDataCapabilityPart;
360+
isDefaultTheme?: boolean;
360361
};
361362

362363
/**

packages/unified-server/src/client/app/elements/app-view/app-view.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ export class AppView extends LitElement {
108108

109109
if (this.config.theme?.splashScreen) {
110110
options.splashImage = true;
111+
options.isDefaultTheme = this.config.isDefautTheme;
111112

112113
// Set the options here, then attempt to load the splash screen image.
113114
this.config.template.options = options;

packages/unified-server/src/client/app/init.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,12 @@ function extractThemeFromFlow(flow: GraphDescriptor | null): {
197197
templateAdditionalOptionsChosen: Record<string, string>;
198198
title: string;
199199
description: string | null;
200+
isDefaultTheme: boolean;
200201
} | null {
201202
const title = flow?.title ?? "Untitled App";
202203
const description: string | null = flow?.description ?? null;
203204

205+
let isDefaultTheme = false;
204206
let templateAdditionalOptionsChosen: Record<string, string> = {};
205207

206208
const theme: AppTheme = createDefaultTheme();
@@ -216,6 +218,7 @@ function extractThemeFromFlow(flow: GraphDescriptor | null): {
216218
const appTheme = themes[graphTheme];
217219
const themeColors = appTheme.themeColors;
218220
const splashScreen = appTheme.splashScreen;
221+
isDefaultTheme = appTheme.isDefaultTheme ?? false;
219222

220223
if (themeColors) {
221224
theme.primaryColor = themeColors["primaryColor"] ?? primaryColor;
@@ -272,6 +275,7 @@ function extractThemeFromFlow(flow: GraphDescriptor | null): {
272275
title,
273276
description,
274277
templateAdditionalOptionsChosen,
278+
isDefaultTheme,
275279
};
276280
}
277281

@@ -315,6 +319,7 @@ async function bootstrap(args: BootstrapArguments = {}) {
315319
theme: extractedTheme?.theme ?? null,
316320
title: extractedTheme?.title ?? null,
317321
description: extractedTheme?.description ?? null,
322+
isDefautTheme: extractedTheme?.isDefaultTheme ?? false,
318323
templateAdditionalOptions:
319324
extractedTheme?.templateAdditionalOptionsChosen ?? null,
320325
};

packages/unified-server/src/client/app/types/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface AppViewConfig {
3131
settingsHelper: SettingsHelperImpl;
3232
runner: Runner | null;
3333
theme: AppTheme | null;
34+
isDefautTheme: boolean;
3435
title: string | null;
3536
description: string | null;
3637
templateAdditionalOptions: Record<string, string> | null;
Loading

packages/visual-editor/src/runtime/board.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -654,19 +654,20 @@ export class Board extends EventTarget {
654654

655655
const graphTheme: GraphTheme = {
656656
themeColors: {
657-
primaryColor: "#246db5",
658-
secondaryColor: "#5cadff",
657+
primaryColor: "#ffffff",
658+
secondaryColor: "#7a7a7a",
659659
backgroundColor: "#ffffff",
660660
textColor: "#1a1a1a",
661-
primaryTextColor: "#ffffff",
661+
primaryTextColor: "#1a1a1a",
662662
},
663663
template: "basic",
664664
splashScreen: {
665665
storedData: {
666-
handle: "/images/app/generic-flow.jpg",
667-
mimeType: "image/jpeg",
666+
handle: MAIN_ICON,
667+
mimeType: "image/svg+xml",
668668
},
669669
},
670+
isDefaultTheme: true,
670671
};
671672

672673
const themeId = globalThis.crypto.randomUUID();

0 commit comments

Comments
 (0)