Skip to content

Commit e35de86

Browse files
authored
experimental: add icons to html elements (#5219)
Ref #3632 <img width="281" alt="Screenshot 2025-05-18 at 18 37 16" src="https://github.com/user-attachments/assets/0b95b674-c9fa-4f5d-b79d-b1ce6023dba8" />
1 parent 90aa424 commit e35de86

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+194
-201
lines changed

apps/builder/app/builder/features/command-panel/command-panel.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import {
3939
} from "~/shared/nano-states";
4040
import {
4141
getComponentTemplateData,
42-
getInstanceLabel,
4342
insertWebstudioFragmentAt,
4443
} from "~/shared/instance-utils";
4544
import { humanizeString } from "~/shared/string-utils";
@@ -50,6 +49,10 @@ import { setActiveSidebarPanel } from "~/builder/shared/nano-states";
5049
import { $commandMetas } from "~/shared/commands-emitter";
5150
import { emitCommand } from "~/builder/shared/commands";
5251
import { isFeatureEnabled } from "@webstudio-is/feature-flags";
52+
import {
53+
getInstanceLabel,
54+
InstanceIcon,
55+
} from "~/builder/shared/instance-label";
5356

5457
const $commandPanel = atom<
5558
| undefined
@@ -88,7 +91,7 @@ type ComponentOption = {
8891
component: string;
8992
label: string;
9093
category: TemplateMeta["category"];
91-
icon: string;
94+
icon: undefined | string;
9295
order: undefined | number;
9396
};
9497

@@ -177,7 +180,7 @@ const $componentOptions = computed(
177180
component: name,
178181
label,
179182
category: meta.category,
180-
icon: meta.icon ?? componentMeta?.icon ?? "",
183+
icon: meta.icon ?? componentMeta?.icon,
181184
order: meta.order,
182185
});
183186
}
@@ -211,9 +214,9 @@ const ComponentOptionsGroup = ({ options }: { options: ComponentOption[] }) => {
211214
}}
212215
>
213216
<Flex gap={2}>
214-
<CommandIcon
215-
dangerouslySetInnerHTML={{ __html: icon }}
216-
></CommandIcon>
217+
<CommandIcon>
218+
<InstanceIcon instance={{ component }} icon={icon} />
219+
</CommandIcon>
217220
<Text variant="labelsTitleCase">
218221
{label}{" "}
219222
<Text as="span" color="moreSubtle">

apps/builder/app/builder/features/components/components.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,30 @@ import {
3131
} from "@webstudio-is/design-system";
3232
import { CollapsibleSection } from "~/builder/shared/collapsible-section";
3333
import { dragItemAttribute, useDraggable } from "./use-draggable";
34-
import { MetaIcon } from "~/builder/shared/meta-icon";
3534
import {
3635
$registeredComponentMetas,
3736
$registeredTemplates,
3837
} from "~/shared/nano-states";
3938
import {
4039
getComponentTemplateData,
41-
getInstanceLabel,
4240
insertWebstudioElementAt,
4341
insertWebstudioFragmentAt,
4442
} from "~/shared/instance-utils";
4543
import type { Publish } from "~/shared/pubsub";
4644
import { $selectedPage } from "~/shared/awareness";
4745
import { mapGroupBy } from "~/shared/shim";
46+
import {
47+
getInstanceLabel,
48+
InstanceIcon,
49+
} from "~/builder/shared/instance-label";
4850

4951
type Meta = {
5052
name: string;
5153
category: string;
5254
order: undefined | number;
5355
label: string;
5456
description: undefined | string;
55-
icon: string;
57+
icon?: string;
5658
};
5759

5860
const $metas = computed(
@@ -85,7 +87,6 @@ const $metas = computed(
8587
order: componentMeta.order,
8688
label: getInstanceLabel({ component: name }, componentMeta),
8789
description: componentMeta.description,
88-
icon: componentMeta.icon,
8990
});
9091
}
9192
for (const [name, templateMeta] of templates) {
@@ -111,7 +112,7 @@ const $metas = computed(
111112
componentMeta?.label ??
112113
getInstanceLabel({ component: name }, templateMeta),
113114
description: templateMeta.description,
114-
icon: templateMeta.icon ?? componentMeta?.icon ?? "",
115+
icon: templateMeta.icon,
115116
});
116117
}
117118
const metasByCategory = mapGroupBy(metas, (meta) => meta.category);
@@ -335,7 +336,14 @@ export const ComponentsPanel = ({
335336
{...{ [dragItemAttribute]: meta.name }}
336337
label={meta.label}
337338
description={meta.description}
338-
icon={<MetaIcon size="auto" icon={meta.icon} />}
339+
icon={
340+
<InstanceIcon
341+
size="auto"
342+
instance={{ component: meta.name }}
343+
// for cases like Sheet template
344+
icon={meta.icon}
345+
/>
346+
}
339347
/>
340348
</ListItem>
341349
))}

apps/builder/app/builder/features/components/use-draggable.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ import {
1010
useDisableCanvasPointerEvents,
1111
rawTheme,
1212
} from "@webstudio-is/design-system";
13-
import { $registeredComponentMetas } from "~/shared/nano-states";
1413
import { useSubscribe, type Publish } from "~/shared/pubsub";
1514
import { $canvasRect, $scale } from "~/builder/shared/nano-states";
16-
import { getInstanceLabel } from "~/shared/instance-utils";
17-
import { MetaIcon } from "~/builder/shared/meta-icon";
15+
import { InstanceIcon, InstanceLabel } from "~/builder/shared/instance-label";
1816

1917
const DragLayer = ({
2018
component,
@@ -23,12 +21,6 @@ const DragLayer = ({
2321
component: Instance["component"];
2422
point: Point;
2523
}) => {
26-
const metas = useStore($registeredComponentMetas);
27-
const meta = metas.get(component);
28-
if (meta === undefined) {
29-
return null;
30-
}
31-
3224
return createPortal(
3325
<Flex
3426
// Container is used to position card
@@ -40,8 +32,8 @@ const DragLayer = ({
4032
}}
4133
>
4234
<ComponentCard
43-
label={getInstanceLabel({ component }, meta)}
44-
icon={<MetaIcon size="auto" icon={meta.icon} />}
35+
label={<InstanceLabel instance={{ component }} />}
36+
icon={<InstanceIcon size="auto" instance={{ component }} />}
4537
style={{
4638
transform: `translate3d(${point.x}px, ${point.y}px, 0)`,
4739
width: rawTheme.spacing[20],

apps/builder/app/builder/features/footer/breadcrumbs.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ import { Fragment } from "react";
22
import { useStore } from "@nanostores/react";
33
import { ChevronRightIcon } from "@webstudio-is/icons";
44
import { theme, Button, Flex, Text } from "@webstudio-is/design-system";
5-
import { $registeredComponentMetas } from "~/shared/nano-states";
65
import { $textEditingInstanceSelector } from "~/shared/nano-states";
7-
import { getInstanceLabel } from "~/shared/instance-utils";
86
import { $selectedInstancePath, selectInstance } from "~/shared/awareness";
7+
import { InstanceLabel } from "~/builder/shared/instance-label";
98

109
export const Breadcrumbs = () => {
1110
const instancePath = useStore($selectedInstancePath);
12-
const metas = useStore($registeredComponentMetas);
1311
return (
1412
<Flex align="center" css={{ height: "100%", px: theme.spacing[3] }}>
1513
{instancePath === undefined ? (
@@ -20,10 +18,6 @@ export const Breadcrumbs = () => {
2018
.slice()
2119
.reverse()
2220
.map(({ instance, instanceSelector }, index) => {
23-
const meta = metas.get(instance.component);
24-
if (meta === undefined) {
25-
return;
26-
}
2721
return (
2822
<Fragment key={index}>
2923
<Button
@@ -35,7 +29,7 @@ export const Breadcrumbs = () => {
3529
$textEditingInstanceSelector.set(undefined);
3630
}}
3731
>
38-
{getInstanceLabel(instance, meta)}
32+
<InstanceLabel instance={instance} />
3933
</Button>
4034
{/* hide the last one */}
4135
{index < instancePath.length - 1 && <ChevronRightIcon />}

apps/builder/app/builder/features/navigator/navigator-tree.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ import {
5555
} from "~/shared/nano-states";
5656
import type { InstanceSelector } from "~/shared/tree-utils";
5757
import { serverSyncStore } from "~/shared/sync";
58-
import { MetaIcon } from "~/builder/shared/meta-icon";
59-
import { getInstanceLabel, reparentInstance } from "~/shared/instance-utils";
58+
import { reparentInstance } from "~/shared/instance-utils";
6059
import { emitCommand } from "~/builder/shared/commands";
6160
import { useContentEditable } from "~/shared/dom-hooks";
6261
import {
@@ -69,6 +68,10 @@ import {
6968
isRichTextContent,
7069
isTreeSatisfyingContentModel,
7170
} from "~/shared/content-model";
71+
import {
72+
getInstanceLabel,
73+
InstanceIcon,
74+
} from "~/builder/shared/instance-label";
7275

7376
type TreeItemAncestor =
7477
| undefined
@@ -430,7 +433,7 @@ const TreeNodeContent = ({
430433
});
431434

432435
return (
433-
<TreeNodeLabel prefix={<MetaIcon icon={meta.icon} />}>
436+
<TreeNodeLabel prefix={<InstanceIcon instance={instance} />}>
434437
<EditableTreeNodeLabel
435438
ref={mergeRefs(editableRef, ref)}
436439
{...handlers}
@@ -657,7 +660,9 @@ export const NavigatorTree = () => {
657660
</Tooltip>
658661
}
659662
>
660-
<TreeNodeLabel prefix={<MetaIcon icon={rootMeta.icon} />}>
663+
<TreeNodeLabel
664+
prefix={<InstanceIcon instance={{ component: rootComponent }} />}
665+
>
661666
{rootMeta.label}
662667
</TreeNodeLabel>
663668
</TreeNode>

apps/builder/app/builder/features/settings-panel/props-section/animation/subject-select.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import {
88
$selectedInstanceSelector,
99
} from "~/shared/nano-states";
1010
import { getInstanceStyleDecl } from "~/builder/features/style-panel/shared/model";
11-
import { getInstanceLabel, updateWebstudioData } from "~/shared/instance-utils";
11+
import { updateWebstudioData } from "~/shared/instance-utils";
1212
import { toValue } from "@webstudio-is/css-engine";
1313
import type { AnimationAction } from "@webstudio-is/sdk";
1414
import { setListedCssProperty } from "./set-css-property";
15+
import { getInstanceLabel } from "~/builder/shared/instance-label";
1516

1617
const initSubjects = () => {
1718
const selectedInstanceSelector = $selectedInstanceSelector.get();

apps/builder/app/builder/features/settings-panel/props-section/props-section.stories.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@ registerComponentLibrary({
202202
templates: {},
203203
metas: {
204204
Box: {
205-
icon: "",
206205
props: {
207206
initialText: textProp("", "multi\nline"),
208207
initialShortText: shortTextProp(),

apps/builder/app/builder/features/settings-panel/settings-section.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import type { Instance } from "@webstudio-is/sdk";
44
import { InputField } from "@webstudio-is/design-system";
55
import { $instances, $registeredComponentMetas } from "~/shared/nano-states";
66
import { HorizontalLayout, Label, Row, useLocalValue } from "./shared";
7-
import { getInstanceLabel } from "~/shared/instance-utils";
87
import { serverSyncStore } from "~/shared/sync";
98
import { $selectedInstance } from "~/shared/awareness";
9+
import { getInstanceLabel } from "~/builder/shared/instance-label";
1010

1111
const saveLabel = (label: string, selectedInstance: Instance) => {
1212
serverSyncStore.createTransaction([$instances], (instances) => {
@@ -32,9 +32,6 @@ export const SettingsSection = () => {
3232
}
3333

3434
const meta = metas.get(selectedInstance.component);
35-
if (meta === undefined) {
36-
return;
37-
}
3835
const placeholder = getInstanceLabel(selectedInstance, meta);
3936

4037
return (

apps/builder/app/builder/features/style-panel/property-label.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import {
2323
$registeredComponentMetas,
2424
$styleSources,
2525
} from "~/shared/nano-states";
26-
import { getInstanceLabel } from "~/shared/instance-utils";
2726
import type {
2827
ComputedStyleDecl,
2928
StyleValueSourceColor,
@@ -32,6 +31,7 @@ import { useComputedStyles } from "./shared/model";
3231
import { StyleSourceBadge } from "./style-source";
3332
import { createBatchUpdate } from "./shared/use-style-data";
3433
import { $virtualInstances } from "~/shared/awareness";
34+
import { getInstanceLabel } from "~/builder/shared/instance-label";
3535

3636
const $isAltPressed = atom(false);
3737
if (typeof window !== "undefined") {

apps/builder/app/builder/features/workspace/canvas-tools/outline/block-instance-outline.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@ import {
1919
} from "@webstudio-is/design-system";
2020
import type { Instance } from "@webstudio-is/sdk";
2121
import { PlusIcon, TrashIcon } from "@webstudio-is/icons";
22-
import { BoxIcon } from "@webstudio-is/icons/svg";
2322
import {
2423
$blockChildOutline,
2524
$hoveredInstanceOutline,
2625
$hoveredInstanceSelector,
2726
$instances,
2827
$isContentMode,
2928
$modifierKeys,
30-
$registeredComponentMetas,
3129
findBlockSelector,
3230
findTemplates,
3331
type BlockChildOutline,
@@ -38,13 +36,13 @@ import {
3836
deleteInstanceMutable,
3937
updateWebstudioData,
4038
} from "~/shared/instance-utils";
41-
import { MetaIcon } from "~/builder/shared/meta-icon";
4239
import { skipInertHandlersAttribute } from "~/builder/shared/inert-handlers";
4340
import { useEffectEvent } from "~/shared/hook-utils/effect-event";
4441
import { getInstancePath } from "~/shared/awareness";
4542
import { insertTemplateAt } from "./block-utils";
4643
import { Outline } from "./outline";
4744
import { applyScale } from "./apply-scale";
45+
import { InstanceIcon } from "~/builder/shared/instance-label";
4846

4947
export const TemplatesMenu = ({
5048
onOpenChange,
@@ -74,7 +72,6 @@ export const TemplatesMenu = ({
7472
preventFocusOnHover: boolean;
7573
}) => {
7674
const instances = useStore($instances);
77-
const metas = useStore($registeredComponentMetas);
7875
const modifierKeys = useStore($modifierKeys);
7976

8077
const blockInstanceSelector = findBlockSelector(anchor, instances);
@@ -105,7 +102,7 @@ export const TemplatesMenu = ({
105102

106103
const menuItems = templates?.map(([template, templateSelector]) => ({
107104
id: template.id,
108-
icon: <MetaIcon icon={metas.get(template.component)?.icon ?? BoxIcon} />,
105+
icon: <InstanceIcon instance={{ component: template.component }} />,
109106
title: template.label ?? template.component,
110107
value: templateSelector,
111108
}));

0 commit comments

Comments
 (0)