@agent-native/core 0.80.0 → 0.80.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +28 -0
- package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +16 -1
- package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +14 -1
- package/corpus/core/docs/content/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/template-design.mdx +14 -1
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/application-state/handlers.ts +1 -1
- package/corpus/core/src/brand-kit/index.ts +1 -1
- package/corpus/core/src/cli/skills.ts +18 -0
- package/corpus/core/src/client/AgentPanel.tsx +1 -1
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +1 -1
- package/corpus/core/src/client/extensions/portable-extension.ts +1 -1
- package/corpus/core/src/code-agents/transcript-normalizer.ts +1 -1
- package/corpus/core/src/extensions/path.ts +1 -4
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +1 -1
- package/corpus/core/src/mcp/build-server.ts +2 -2
- package/corpus/core/src/mcp/embed-app.ts +35 -1
- package/corpus/core/src/org/handlers.ts +5 -5
- package/corpus/core/src/org/plugin.ts +2 -2
- package/corpus/core/src/scripts/call-agent.ts +1 -1
- package/corpus/core/src/scripts/db/safety.ts +1 -1
- package/corpus/core/src/server/auth.ts +3 -0
- package/corpus/core/src/server/builder-design-systems.ts +308 -0
- package/corpus/core/src/server/core-routes-plugin.ts +29 -3
- package/corpus/core/src/server/index.ts +8 -0
- package/corpus/core/src/styles/agent-native.css +14 -7
- package/corpus/core/src/usage/store.ts +2 -2
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +298 -15
- package/corpus/templates/analytics/actions/get-sql-dashboard.ts +9 -4
- package/corpus/templates/analytics/actions/mutate-dashboard.ts +18 -2
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +12 -2
- package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +66 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +37 -0
- package/corpus/templates/analytics/app/i18n-data.ts +404 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +333 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +121 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +49 -26
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +137 -36
- package/corpus/templates/analytics/changelog/2026-06-29-analytics-agents-can-now-place-new-charts-into-requested-das.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-analytics-queries-now-report-failed-source-query-errors-inst.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-charts-can-now-be-dropped-between-full-dashboard-rows-to-cre.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-dashboard-email-reports-include-the-full-dashboard-image-wit.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-main-surface-border-reaches-the-top.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-session-replay-now-records-playable-sessions-in-production-a.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-set-up-session-replay-storage-from-settings-connect-builder-.md +6 -0
- package/corpus/templates/analytics/scripts/cleanup-empty-session-recordings.ts +102 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +49 -26
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +81 -20
- package/corpus/templates/analytics/server/lib/replay-storage.ts +79 -0
- package/corpus/templates/analytics/server/lib/s3-upload-provider.ts +255 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +29 -8
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -2
- package/corpus/templates/analytics/server/plugins/onboarding.ts +97 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +24 -0
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +105 -5
- package/corpus/templates/content/actions/set-image-alt-text.ts +1 -1
- package/corpus/templates/content/shared/document-export.ts +1 -1
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -18
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
- package/corpus/templates/design/actions/add-localhost-screens.ts +32 -5
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +259 -0
- package/corpus/templates/design/actions/update-file.ts +9 -2
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +33 -75
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +72 -9
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +41 -39
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1029 -249
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +450 -101
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +978 -154
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -9
- package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +133 -66
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +1234 -344
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +144 -94
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +301 -72
- package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +876 -286
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +601 -0
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +242 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +30 -7
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +212 -155
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +423 -0
- package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +487 -107
- package/corpus/templates/design/app/components/design/inspector/index.ts +27 -0
- package/corpus/templates/design/app/global.css +29 -3
- package/corpus/templates/design/app/i18n/zh-TW.ts +13 -0
- package/corpus/templates/design/app/i18n-data.ts +239 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +1023 -353
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +57 -221
- package/corpus/templates/design/changelog/2026-06-29-canvas-selection-no-longer-flashes-broken-prototype-html-whe.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-command-menu-selections-are-clearer-in-dark-mode.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-element-selection-now-stays-on-the-intended-layer-after-sele.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-full-view-controls-now-sit-above-frames-inst.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-tools-can-draw-shapes-create-screens-and-kee.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-now-creates-anchor-based-bezier-vectors-with-ha.md +6 -0
- package/corpus/templates/design/server/handlers/import-figma-system.ts +38 -85
- package/corpus/templates/design/server/lib/design-snapshot.ts +9 -1
- package/corpus/templates/design/shared/code-layer.ts +209 -9
- package/corpus/templates/design/shared/html-content.ts +21 -0
- package/corpus/templates/design/shared/pen-path.ts +207 -0
- package/corpus/templates/mail/app/lib/utils.ts +2 -2
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -10
- package/corpus/templates/slides/AGENTS.md +3 -2
- package/corpus/templates/slides/actions/import-file.ts +26 -17
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +259 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +35 -167
- package/corpus/templates/slides/app/components/design-system/fig-import-response.ts +9 -13
- package/corpus/templates/slides/app/context/DeckContext.tsx +1 -1
- package/corpus/templates/slides/app/i18n/ar-SA.ts +9 -37
- package/corpus/templates/slides/app/i18n/de-DE.ts +10 -25
- package/corpus/templates/slides/app/i18n/en-US.ts +9 -26
- package/corpus/templates/slides/app/i18n/es-ES.ts +10 -28
- package/corpus/templates/slides/app/i18n/fr-FR.ts +10 -28
- package/corpus/templates/slides/app/i18n/hi-IN.ts +9 -26
- package/corpus/templates/slides/app/i18n/ja-JP.ts +10 -22
- package/corpus/templates/slides/app/i18n/ko-KR.ts +9 -23
- package/corpus/templates/slides/app/i18n/pt-BR.ts +10 -28
- package/corpus/templates/slides/app/i18n/zh-CN.ts +9 -22
- package/corpus/templates/slides/app/i18n/zh-TW.ts +9 -22
- package/corpus/templates/slides/server/handlers/import-figma-system.ts +44 -12
- package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
- package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +1 -1
- package/dist/application-state/handlers.js +1 -1
- package/dist/application-state/handlers.js.map +1 -1
- package/dist/brand-kit/index.d.ts +1 -1
- package/dist/brand-kit/index.js +1 -1
- package/dist/brand-kit/index.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +18 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/extensions/portable-extension.d.ts +1 -1
- package/dist/client/extensions/portable-extension.d.ts.map +1 -1
- package/dist/client/extensions/portable-extension.js.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +1 -1
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/extensions/path.d.ts +1 -1
- package/dist/extensions/path.d.ts.map +1 -1
- package/dist/extensions/path.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/integrations/a2a-continuation-processor.js +1 -1
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/mcp/build-server.d.ts +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +1 -1
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +35 -1
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +8 -8
- package/dist/org/handlers.js +5 -5
- package/dist/org/handlers.js.map +1 -1
- package/dist/org/plugin.js +2 -2
- package/dist/org/plugin.js.map +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/call-agent.js +1 -1
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/scripts/db/safety.js +1 -1
- package/dist/scripts/db/safety.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +3 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts +28 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -0
- package/dist/server/builder-design-systems.js +217 -0
- package/dist/server/builder-design-systems.js.map +1 -0
- package/dist/server/core-routes-plugin.d.ts +1 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +20 -3
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/styles/agent-native.css +14 -7
- package/dist/usage/store.js +2 -2
- package/dist/usage/store.js.map +1 -1
- package/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
- package/docs/content/locales/ar-SA/template-design.mdx +14 -1
- package/docs/content/locales/de-DE/skills-guide.mdx +5 -0
- package/docs/content/locales/de-DE/template-design.mdx +15 -1
- package/docs/content/locales/es-ES/skills-guide.mdx +5 -0
- package/docs/content/locales/es-ES/template-design.mdx +15 -1
- package/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
- package/docs/content/locales/fr-FR/template-design.mdx +15 -1
- package/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
- package/docs/content/locales/hi-IN/template-design.mdx +15 -1
- package/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
- package/docs/content/locales/ja-JP/template-design.mdx +16 -1
- package/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
- package/docs/content/locales/ko-KR/template-design.mdx +14 -1
- package/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
- package/docs/content/locales/pt-BR/template-design.mdx +14 -1
- package/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
- package/docs/content/locales/zh-CN/template-design.mdx +14 -1
- package/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
- package/docs/content/locales/zh-TW/template-design.mdx +14 -1
- package/docs/content/skills-guide.mdx +5 -0
- package/docs/content/template-design.mdx +14 -1
- package/package.json +1 -1
- package/corpus/templates/design/actions/import-figma-file.ts +0 -166
- package/corpus/templates/slides/server/lib/fig-design-system.ts +0 -110
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { useActionMutation } from "@agent-native/core/client";
|
|
2
|
+
import {
|
|
3
|
+
Dithering,
|
|
4
|
+
GodRays,
|
|
5
|
+
GrainGradient,
|
|
6
|
+
MeshGradient,
|
|
7
|
+
Metaballs,
|
|
8
|
+
PaperTexture,
|
|
9
|
+
Voronoi,
|
|
10
|
+
Warp,
|
|
11
|
+
} from "@paper-design/shaders-react";
|
|
12
|
+
import {
|
|
13
|
+
SHADER_PRESET_MAP,
|
|
14
|
+
SHADER_PRESETS,
|
|
15
|
+
type ShaderDescriptor,
|
|
16
|
+
type ShaderPresetDef,
|
|
17
|
+
type ShaderPresetName,
|
|
18
|
+
} from "@shared/shader-presets";
|
|
19
|
+
import { buildFallbackGradient, isWebGLAvailable } from "@shared/shader-safety";
|
|
20
|
+
import {
|
|
21
|
+
IconArrowLeft,
|
|
22
|
+
IconPlus,
|
|
23
|
+
IconSearch,
|
|
24
|
+
IconX,
|
|
25
|
+
} from "@tabler/icons-react";
|
|
26
|
+
import { Component, useMemo, useState, type ReactNode } from "react";
|
|
27
|
+
|
|
28
|
+
import { Input } from "@/components/ui/input";
|
|
29
|
+
import {
|
|
30
|
+
Tooltip,
|
|
31
|
+
TooltipContent,
|
|
32
|
+
TooltipTrigger,
|
|
33
|
+
} from "@/components/ui/tooltip";
|
|
34
|
+
import { cn } from "@/lib/utils";
|
|
35
|
+
|
|
36
|
+
import { ShaderControls } from "./ShaderControls";
|
|
37
|
+
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
type AnyShaderComponent = React.ComponentType<Record<string, any>>;
|
|
40
|
+
|
|
41
|
+
const SHADER_COMPONENTS: Record<ShaderPresetName, AnyShaderComponent> = {
|
|
42
|
+
MeshGradient: MeshGradient as AnyShaderComponent,
|
|
43
|
+
GrainGradient: GrainGradient as AnyShaderComponent,
|
|
44
|
+
Voronoi: Voronoi as AnyShaderComponent,
|
|
45
|
+
Metaballs: Metaballs as AnyShaderComponent,
|
|
46
|
+
Warp: Warp as AnyShaderComponent,
|
|
47
|
+
GodRays: GodRays as AnyShaderComponent,
|
|
48
|
+
Dithering: Dithering as AnyShaderComponent,
|
|
49
|
+
PaperTexture: PaperTexture as AnyShaderComponent,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// ─── Descriptor helpers ────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
/** Build a fresh descriptor with the preset's default params + colors. */
|
|
55
|
+
export function descriptorFromPreset(
|
|
56
|
+
preset: ShaderPresetDef,
|
|
57
|
+
): ShaderDescriptor {
|
|
58
|
+
const params: Record<string, number | boolean | string> = {};
|
|
59
|
+
for (const p of preset.params) {
|
|
60
|
+
if (p.kind !== "colors" && !Array.isArray(p.default)) {
|
|
61
|
+
params[p.key] = p.default as number | boolean | string;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
preset: preset.name,
|
|
66
|
+
params,
|
|
67
|
+
colors: preset.defaultColors ?? undefined,
|
|
68
|
+
speed: 0,
|
|
69
|
+
frame: 0,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A static CSS fallback fill for a shader descriptor. The live WebGL shader is
|
|
75
|
+
* GPU-only; for the element fill we apply a representative gradient so the
|
|
76
|
+
* picker stays functional everywhere. The full descriptor is validated and
|
|
77
|
+
* surfaced via the apply-shader action so the agent can write real shader code.
|
|
78
|
+
*/
|
|
79
|
+
export function shaderDescriptorToCss(descriptor: ShaderDescriptor): string {
|
|
80
|
+
const preset = SHADER_PRESET_MAP[descriptor.preset];
|
|
81
|
+
const colors =
|
|
82
|
+
descriptor.colors && descriptor.colors.length > 0
|
|
83
|
+
? descriptor.colors
|
|
84
|
+
: (preset?.defaultColors ?? []);
|
|
85
|
+
return buildFallbackGradient(colors, preset?.defaultColorBack);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ─── Live thumbnail ────────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
/** Catches WebGL/render errors from the live shader and shows a CSS fallback. */
|
|
91
|
+
class ShaderBoundary extends Component<
|
|
92
|
+
{ fallback: ReactNode; children: ReactNode },
|
|
93
|
+
{ failed: boolean }
|
|
94
|
+
> {
|
|
95
|
+
state = { failed: false };
|
|
96
|
+
static getDerivedStateFromError() {
|
|
97
|
+
return { failed: true };
|
|
98
|
+
}
|
|
99
|
+
render() {
|
|
100
|
+
return this.state.failed ? this.props.fallback : this.props.children;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function ShaderThumbnail({
|
|
105
|
+
preset,
|
|
106
|
+
selected,
|
|
107
|
+
}: {
|
|
108
|
+
preset: ShaderPresetDef;
|
|
109
|
+
selected: boolean;
|
|
110
|
+
}) {
|
|
111
|
+
const ShaderComponent = SHADER_COMPONENTS[preset.name];
|
|
112
|
+
const webglOk = isWebGLAvailable();
|
|
113
|
+
|
|
114
|
+
const fallback = buildFallbackGradient(
|
|
115
|
+
preset.defaultColors ?? [preset.defaultColorFront ?? "#888888"],
|
|
116
|
+
preset.defaultColorBack,
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const shaderProps = useMemo(() => {
|
|
120
|
+
const p: Record<string, unknown> = {};
|
|
121
|
+
for (const def of preset.params) {
|
|
122
|
+
if (def.kind !== "colors" && !Array.isArray(def.default)) {
|
|
123
|
+
p[def.key] = def.default;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (preset.defaultColors) p.colors = preset.defaultColors;
|
|
127
|
+
if (preset.defaultColorBack) p.colorBack = preset.defaultColorBack;
|
|
128
|
+
if (preset.defaultColorFront) p.colorFront = preset.defaultColorFront;
|
|
129
|
+
// Static thumbnail — no animation churn in a grid of 8 live canvases.
|
|
130
|
+
p.speed = 0;
|
|
131
|
+
p.frame = 0;
|
|
132
|
+
return p;
|
|
133
|
+
}, [preset]);
|
|
134
|
+
|
|
135
|
+
const fallbackEl = (
|
|
136
|
+
<div className="absolute inset-0" style={{ background: fallback }} />
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div
|
|
141
|
+
className={cn(
|
|
142
|
+
"relative aspect-[4/3] w-full overflow-hidden rounded-md border transition-colors",
|
|
143
|
+
selected
|
|
144
|
+
? "border-primary shadow-[0_0_0_1px_var(--primary)]"
|
|
145
|
+
: "border-border/60 group-hover:border-foreground/40",
|
|
146
|
+
)}
|
|
147
|
+
>
|
|
148
|
+
{webglOk ? (
|
|
149
|
+
<ShaderBoundary fallback={fallbackEl}>
|
|
150
|
+
<ShaderComponent
|
|
151
|
+
{...shaderProps}
|
|
152
|
+
style={{
|
|
153
|
+
position: "absolute",
|
|
154
|
+
inset: 0,
|
|
155
|
+
width: "100%",
|
|
156
|
+
height: "100%",
|
|
157
|
+
}}
|
|
158
|
+
/>
|
|
159
|
+
</ShaderBoundary>
|
|
160
|
+
) : (
|
|
161
|
+
fallbackEl
|
|
162
|
+
)}
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ─── Component ─────────────────────────────────────────────────────────────────
|
|
168
|
+
|
|
169
|
+
export interface ShaderFillsPanelProps {
|
|
170
|
+
/** Currently-applied shader descriptor, if the fill is already a shader. */
|
|
171
|
+
descriptor?: ShaderDescriptor;
|
|
172
|
+
/** Emits when the user applies/tunes a shader. value = CSS fallback fill. */
|
|
173
|
+
onApply: (descriptor: ShaderDescriptor, css: string) => void;
|
|
174
|
+
/** Close the shader panel and return to the color picker. */
|
|
175
|
+
onBack: () => void;
|
|
176
|
+
/** Optional design context forwarded to the apply-shader action. */
|
|
177
|
+
applyContext?: {
|
|
178
|
+
designId?: string;
|
|
179
|
+
fileId?: string;
|
|
180
|
+
nodeId?: string;
|
|
181
|
+
selector?: string;
|
|
182
|
+
};
|
|
183
|
+
disabled?: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function ShaderFillsPanel({
|
|
187
|
+
descriptor,
|
|
188
|
+
onApply,
|
|
189
|
+
onBack,
|
|
190
|
+
applyContext,
|
|
191
|
+
disabled = false,
|
|
192
|
+
}: ShaderFillsPanelProps) {
|
|
193
|
+
const [search, setSearch] = useState("");
|
|
194
|
+
const [active, setActive] = useState<ShaderDescriptor | null>(
|
|
195
|
+
descriptor ?? null,
|
|
196
|
+
);
|
|
197
|
+
const applyShader = useActionMutation("apply-shader");
|
|
198
|
+
|
|
199
|
+
const filtered = useMemo(() => {
|
|
200
|
+
const query = search.trim().toLowerCase();
|
|
201
|
+
if (!query) return SHADER_PRESETS;
|
|
202
|
+
return SHADER_PRESETS.filter(
|
|
203
|
+
(preset) =>
|
|
204
|
+
preset.label.toLowerCase().includes(query) ||
|
|
205
|
+
preset.description.toLowerCase().includes(query),
|
|
206
|
+
);
|
|
207
|
+
}, [search]);
|
|
208
|
+
|
|
209
|
+
/** Validate + surface the descriptor for the agent, then emit the CSS fill. */
|
|
210
|
+
const commit = (next: ShaderDescriptor) => {
|
|
211
|
+
setActive(next);
|
|
212
|
+
const css = shaderDescriptorToCss(next);
|
|
213
|
+
onApply(next, css);
|
|
214
|
+
// Fire-and-forget validation/codegen so the agent can write real shader
|
|
215
|
+
// code. The picker fill is applied immediately above regardless of result.
|
|
216
|
+
applyShader.mutate(
|
|
217
|
+
{
|
|
218
|
+
surface: SHADER_PRESET_MAP[next.preset]?.isEffect ? "effect" : "fill",
|
|
219
|
+
descriptor: {
|
|
220
|
+
preset: next.preset,
|
|
221
|
+
params: next.params,
|
|
222
|
+
colors: next.colors,
|
|
223
|
+
speed: next.speed,
|
|
224
|
+
frame: next.frame,
|
|
225
|
+
fit: next.fit,
|
|
226
|
+
scale: next.scale,
|
|
227
|
+
rotation: next.rotation,
|
|
228
|
+
offsetX: next.offsetX,
|
|
229
|
+
offsetY: next.offsetY,
|
|
230
|
+
},
|
|
231
|
+
...(applyContext?.designId || applyContext?.fileId
|
|
232
|
+
? {
|
|
233
|
+
source: {
|
|
234
|
+
kind: "design-file" as const,
|
|
235
|
+
designId: applyContext.designId,
|
|
236
|
+
fileId: applyContext.fileId,
|
|
237
|
+
},
|
|
238
|
+
}
|
|
239
|
+
: {}),
|
|
240
|
+
...(applyContext?.nodeId || applyContext?.selector
|
|
241
|
+
? {
|
|
242
|
+
target: {
|
|
243
|
+
nodeId: applyContext.nodeId,
|
|
244
|
+
selector: applyContext.selector,
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
: {}),
|
|
248
|
+
},
|
|
249
|
+
{ onError: () => undefined },
|
|
250
|
+
);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// ── Detail view: a preset is selected → tune it with ShaderControls ───────
|
|
254
|
+
if (active) {
|
|
255
|
+
const preset = SHADER_PRESET_MAP[active.preset];
|
|
256
|
+
return (
|
|
257
|
+
<div className="flex flex-col">
|
|
258
|
+
{/* Detail header: ← preset-name × */}
|
|
259
|
+
<div className="flex h-6 items-center gap-1.5 px-3">
|
|
260
|
+
<button
|
|
261
|
+
type="button"
|
|
262
|
+
aria-label={"Back to shader fills" /* i18n-ignore */}
|
|
263
|
+
onClick={() => setActive(null)}
|
|
264
|
+
className="flex size-5 items-center justify-center rounded text-muted-foreground hover:bg-[var(--design-editor-control-bg)] hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
265
|
+
>
|
|
266
|
+
<IconArrowLeft className="size-3.5" />
|
|
267
|
+
</button>
|
|
268
|
+
<span className="flex-1 truncate text-[11px] font-semibold text-foreground">
|
|
269
|
+
{preset?.label ?? active.preset}
|
|
270
|
+
</span>
|
|
271
|
+
<button
|
|
272
|
+
type="button"
|
|
273
|
+
aria-label={"Close shader fills" /* i18n-ignore */}
|
|
274
|
+
onClick={onBack}
|
|
275
|
+
className="flex size-5 items-center justify-center rounded text-muted-foreground hover:bg-[var(--design-editor-control-bg)] hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
276
|
+
>
|
|
277
|
+
<IconX className="size-3" />
|
|
278
|
+
</button>
|
|
279
|
+
</div>
|
|
280
|
+
<div className="border-t border-border/70 p-2">
|
|
281
|
+
<ShaderControls
|
|
282
|
+
descriptor={active}
|
|
283
|
+
onChange={(next) => commit(next)}
|
|
284
|
+
/>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ── Browse view: Figma-style title + search + Created by you + By Figma ───
|
|
291
|
+
return (
|
|
292
|
+
<div className="flex flex-col">
|
|
293
|
+
{/* Header: "Shader fills" title + + button + × button */}
|
|
294
|
+
<div className="flex h-6 items-center gap-1 px-3">
|
|
295
|
+
<span className="flex-1 truncate text-[11px] font-semibold text-foreground">
|
|
296
|
+
{"Shader fills" /* i18n-ignore Figma panel title */}
|
|
297
|
+
</span>
|
|
298
|
+
<Tooltip>
|
|
299
|
+
<TooltipTrigger asChild>
|
|
300
|
+
<button
|
|
301
|
+
type="button"
|
|
302
|
+
aria-label={"Create new shader" /* i18n-ignore */}
|
|
303
|
+
disabled={disabled}
|
|
304
|
+
onClick={() => commit(descriptorFromPreset(SHADER_PRESETS[0]))}
|
|
305
|
+
className="flex size-5 items-center justify-center rounded text-muted-foreground hover:bg-[var(--design-editor-control-bg)] hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40"
|
|
306
|
+
>
|
|
307
|
+
<IconPlus className="size-3.5" />
|
|
308
|
+
</button>
|
|
309
|
+
</TooltipTrigger>
|
|
310
|
+
<TooltipContent>
|
|
311
|
+
{"Create new shader" /* i18n-ignore */}
|
|
312
|
+
</TooltipContent>
|
|
313
|
+
</Tooltip>
|
|
314
|
+
<button
|
|
315
|
+
type="button"
|
|
316
|
+
aria-label={"Close shader fills" /* i18n-ignore */}
|
|
317
|
+
onClick={onBack}
|
|
318
|
+
className="flex size-5 items-center justify-center rounded text-muted-foreground hover:bg-[var(--design-editor-control-bg)] hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
319
|
+
>
|
|
320
|
+
<IconX className="size-3" />
|
|
321
|
+
</button>
|
|
322
|
+
</div>
|
|
323
|
+
|
|
324
|
+
{/* Search field */}
|
|
325
|
+
<div className="border-t border-border/70 px-3 py-2">
|
|
326
|
+
<div className="flex h-6 items-center gap-1.5 rounded-md border border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] px-2">
|
|
327
|
+
<IconSearch className="size-3 shrink-0 text-muted-foreground" />
|
|
328
|
+
<Input
|
|
329
|
+
value={search}
|
|
330
|
+
disabled={disabled}
|
|
331
|
+
placeholder={"Search" /* i18n-ignore */}
|
|
332
|
+
aria-label={"Search shaders" /* i18n-ignore */}
|
|
333
|
+
className="h-full min-w-0 flex-1 border-0 bg-transparent p-0 text-[11px] shadow-none focus-visible:ring-0"
|
|
334
|
+
onChange={(event) => setSearch(event.target.value)}
|
|
335
|
+
/>
|
|
336
|
+
{search && (
|
|
337
|
+
<button
|
|
338
|
+
type="button"
|
|
339
|
+
aria-label={"Clear search" /* i18n-ignore */}
|
|
340
|
+
onClick={() => setSearch("")}
|
|
341
|
+
className="flex size-4 items-center justify-center rounded text-muted-foreground hover:text-foreground"
|
|
342
|
+
>
|
|
343
|
+
<IconX className="size-3" />
|
|
344
|
+
</button>
|
|
345
|
+
)}
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
<div className="max-h-[360px] overflow-y-auto px-3 pb-3">
|
|
350
|
+
{/* ── Created by you ── */}
|
|
351
|
+
{!search && (
|
|
352
|
+
<section className="mb-3">
|
|
353
|
+
<p className="mb-1.5 text-[10px] font-semibold text-muted-foreground">
|
|
354
|
+
{"Created by you" /* i18n-ignore Figma section */}
|
|
355
|
+
</p>
|
|
356
|
+
{/* 2-col grid — "Create new" tile occupies the first cell */}
|
|
357
|
+
<div className="grid grid-cols-2 gap-2">
|
|
358
|
+
<button
|
|
359
|
+
type="button"
|
|
360
|
+
disabled={disabled}
|
|
361
|
+
onClick={() => commit(descriptorFromPreset(SHADER_PRESETS[0]))}
|
|
362
|
+
className={cn(
|
|
363
|
+
"group relative flex aspect-[4/3] w-full flex-col items-center justify-center gap-1 rounded-md border border-dashed border-[var(--design-editor-control-border)] text-muted-foreground transition-colors",
|
|
364
|
+
"hover:border-foreground/40 hover:text-foreground",
|
|
365
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
366
|
+
disabled && "pointer-events-none opacity-40",
|
|
367
|
+
)}
|
|
368
|
+
>
|
|
369
|
+
{/* AI badge — top-right corner */}
|
|
370
|
+
<span className="absolute right-1.5 top-1.5 rounded bg-[var(--design-editor-control-bg)] px-1 py-px text-[9px] font-semibold leading-none text-muted-foreground">
|
|
371
|
+
{"AI" /* i18n-ignore */}
|
|
372
|
+
</span>
|
|
373
|
+
<IconPlus className="size-4" />
|
|
374
|
+
<span className="text-[10px]">
|
|
375
|
+
{"Create new" /* i18n-ignore Figma create tile */}
|
|
376
|
+
</span>
|
|
377
|
+
</button>
|
|
378
|
+
</div>
|
|
379
|
+
</section>
|
|
380
|
+
)}
|
|
381
|
+
|
|
382
|
+
{/* ── By Figma — 2-col preset thumbnail grid ── */}
|
|
383
|
+
<section>
|
|
384
|
+
{!search && (
|
|
385
|
+
<p className="mb-1.5 text-[10px] font-semibold text-muted-foreground">
|
|
386
|
+
{"By Figma" /* i18n-ignore Figma section */}
|
|
387
|
+
</p>
|
|
388
|
+
)}
|
|
389
|
+
{filtered.length === 0 ? (
|
|
390
|
+
<p className="py-4 text-center text-[11px] text-muted-foreground">
|
|
391
|
+
{"No shaders match your search" /* i18n-ignore */}
|
|
392
|
+
</p>
|
|
393
|
+
) : (
|
|
394
|
+
<div className="grid grid-cols-2 gap-2">
|
|
395
|
+
{filtered.map((preset) => (
|
|
396
|
+
<Tooltip key={preset.name}>
|
|
397
|
+
<TooltipTrigger asChild>
|
|
398
|
+
<button
|
|
399
|
+
type="button"
|
|
400
|
+
disabled={disabled}
|
|
401
|
+
aria-label={preset.label}
|
|
402
|
+
onClick={() => commit(descriptorFromPreset(preset))}
|
|
403
|
+
className={cn(
|
|
404
|
+
"group flex flex-col gap-1 text-left focus-visible:outline-none",
|
|
405
|
+
disabled && "pointer-events-none opacity-40",
|
|
406
|
+
)}
|
|
407
|
+
>
|
|
408
|
+
<ShaderThumbnail preset={preset} selected={false} />
|
|
409
|
+
<span className="truncate text-[10px] text-muted-foreground group-hover:text-foreground">
|
|
410
|
+
{preset.label}
|
|
411
|
+
</span>
|
|
412
|
+
</button>
|
|
413
|
+
</TooltipTrigger>
|
|
414
|
+
<TooltipContent>{preset.description}</TooltipContent>
|
|
415
|
+
</Tooltip>
|
|
416
|
+
))}
|
|
417
|
+
</div>
|
|
418
|
+
)}
|
|
419
|
+
</section>
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
);
|
|
423
|
+
}
|