Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vectorizer and design essentials plugins #9

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions examples/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
"dependencies": {
"@imgly/plugin-background-removal-web": "*",
"@imgly/plugin-remote-asset-source-web": "*",
"@imgly/plugin-vectorizer": "*",
"@imgly/plugin-design-essentials": "*",
"@cesdk/cesdk-js": "^1.21.0",
"lodash": "^4.17.21",
"react-cmdk": "^1.3.9",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand Down
294 changes: 245 additions & 49 deletions examples/web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,253 @@
import CreativeEditorSDK from '@cesdk/cesdk-js';
import { useRef } from 'react';
const ENABLE_DEMO_ASSET_SOURCES = false;

import { useRef, useState } from "react";
import CreativeEditorSDKComponent from "./components/CreativeEditorSDK";
import CreativeEditorSDK from "@cesdk/cesdk-js";


// React UI Components
import { CommandPalette } from "./components/CommandPalette"
// Utils
import { downloadBlocks } from "./utils/download";

// IMGLY Plugins


// Plugins
// import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web';
import { PluginContext } from "@imgly/plugin-core";

import BackgroundRemovalPlugin from '@imgly/plugin-background-removal-web';
import VectorizerPlugin from '@imgly/plugin-vectorizer';
import DesignBatteriesPlugin from "@imgly/plugin-design-essentials";
import RemoteAssetSourcePlugin from '@imgly/plugin-remote-asset-source-web';




declare global {
interface Window { imgly: PluginContext }
}

import addPlugins, { prepareAssetEntries } from './addPlugins';

function App() {
const cesdk = useRef<CreativeEditorSDK>();
return (
<div
style={{ width: '100vw', height: '100vh' }}
ref={(domElement) => {
if (domElement != null) {
CreativeEditorSDK.create(domElement, {
license: import.meta.env.VITE_CESDK_LICENSE_KEY,
callbacks: { onUpload: 'local' },
ui: {
elements: {
libraries: {
insert: {
entries: (d) => {
if (!cesdk.current) return;
return prepareAssetEntries(d, cesdk.current!.engine);
}
},
replace: {
entries: (d) => {
if (!cesdk.current) return;
return prepareAssetEntries(d, cesdk.current!.engine);
}
}
},
panels: { settings: true }
}
}
}).then(async (instance) => {
// @ts-ignore
window.cesdk = instance;
cesdk.current = instance;

// Do something with the instance of CreativeEditor SDK, for example:
// Populate the asset library with default / demo asset sources.
await Promise.all([
instance.addDefaultAssetSources(),
instance.addDemoAssetSources({ sceneMode: 'Design' })
]);
await addPlugins(instance);
await instance.createDesignScene();
});
} else if (cesdk.current != null) {
cesdk.current.dispose();
// const cesdkRef = useRef<CreativeEditorSDK>();
const contextRef = useRef<PluginContext>();
const [commandItems, setCommandItems] = useState<Array<any>>([])
const [isCommandPaletteOpen, setIsCommandPaletteOpen] = useState<boolean>(false)


const commandPaletteButton = (params: { builder: any }) => {
params
.builder!
.Button("plugin.imgly.commandpalette.id", {
label: "plugin.imgly.commandpalette.label",
icon: undefined,
isActive: isCommandPaletteOpen,
isLoading: false,
isDisabled: isCommandPaletteOpen,
loadingProgress: undefined, // creates infinite spinner
onClick: () => {
setIsCommandPaletteOpen(true)
}
}}
></div>
});
}



const [config, _setConfig] = useState<Object>(
{
"license": import.meta.env.VITE_CESDK_LICENSE_KEY,
"callbacks.onUpload": 'local',
"callbacks.onDownload": "download",
"callbacks.onSave": async (str: string) => downloadBlocks(contextRef.current!.engine.block, [new Blob([str])], { mimeType: 'application/imgly' }),
"callbacks.onExport": async (blobs: Array<Blob>, options: any) => downloadBlocks(contextRef.current!.engine.block, blobs, { mimeType: options.mimeType, pages: options.pages }),
// "callbacks.onLoad": ,
// devMode: true,
"theme": "dark",
"role": 'Creator',
"ui.hide": false,
"ui.elements.view": "advanced",
"ui.elements.navigation.action.save": true,
"ui.elements.navigation.action.load": true,
"ui.elements.navigation.action.export": true,
})


const initCallback = async (cesdk: CreativeEditorSDK) => {

const imgly = new PluginContext(cesdk)
window.imgly = imgly


// Init Scene Programatically
await cesdk.createDesignScene();
cesdk.engine.scene.setDesignUnit("Pixel"); //


const backgroundRemovalPlugin = BackgroundRemovalPlugin({ ui: { locations: 'canvasMenu' } })
const vectorizerPlugin = VectorizerPlugin(imgly, {})
const commandsPlugin = DesignBatteriesPlugin(imgly, {})

// Register Plguins
await Promise.all([
cesdk.addDefaultAssetSources(),
cesdk.addDemoAssetSources({ sceneMode: "Design" }),
cesdk.unstable_addPlugin(commandsPlugin),
cesdk.unstable_addPlugin(vectorizerPlugin),
cesdk.unstable_addPlugin(backgroundRemovalPlugin),
...addDemoRemoteAssetSourcesPlugins(cesdk) //FIXME
]);



// Ui components
imgly.ui?.unstable_registerComponent("plugin.imgly.commandpalette", commandPaletteButton);

imgly.i18n.setTranslations({ en: { "plugin.imgly.commandpalette.label": "✨ Run .." } })
// Canvas Menu
const canvasMenuItems = imgly.ui?.unstable_getCanvasMenuOrder() ?? []
const newCanvasMenuItems = ["plugin.imgly.commandpalette", ...canvasMenuItems];
imgly.ui?.unstable_setCanvasMenuOrder(newCanvasMenuItems)



// Bind our react command paltte to cesdk command palettes are listen on new commands being created
imgly.engine.event.subscribe([], (events) => {
events
.forEach(_ => {
setCommandItems(generateItems(imgly))
})
})
imgly.commands.subscribe("register", (_label: string) => setCommandItems(generateItems(imgly)))
imgly.commands.subscribe("unregister", (_label: string) => setCommandItems(generateItems(imgly)))

setCommandItems(generateItems(imgly))
}


return (
<>
<CommandPalette items={commandItems} isOpen={isCommandPaletteOpen} setIsOpen={(val) => setIsCommandPaletteOpen(val)} />
<CreativeEditorSDKComponent config={config} callback={initCallback} />

</>
);
}

const generateItems = (ctx: PluginContext) => {
return [...generateBlockHierarchy(ctx), ...generateCommandItems(ctx), ...generateProperyItems(ctx)]
}

const generateBlockHierarchy = (ctx: PluginContext) => {
const blocks = ctx.engine.block.findAll()

return blocks.map((bId: number) => {
const titel = ctx.engine.block.getName(bId) || ctx.engine.block.getUUID(bId).toString()
return {
id: bId,
children: titel,
kind: "block",
group: "Hierarchy",
showType: false,
onClick: () => ctx.engine.block.select(bId)
}
})
}

const generateProperyItems = (ctx: PluginContext) => {
const { block } = ctx.engine
const bIds = block.findAllSelected()
const bId = bIds[0]
if (!bId) return [] // for now

const props = bIds.flatMap((bId: number) => block.findAllProperties(bId))
const uniqueProps = Array.from(new Set(props))

return uniqueProps.map((p) => {
const titel = p
const value = 42

return {
id: bId,
children: titel,
kind: "property",
group: "Properties",
showType: false,
onClick: () => prompt(`Change ${p} to`, value.toString())
}
})
}


const generateCommandItems = (ctx: PluginContext): Array<any> => {
const cmds = ctx
.commands!
.listCommands()

return cmds
.map((cmdId: string) => {
const titel = ctx.i18n.translate(cmdId) // this comes from the metadata
const desc = ctx.commands.getCommandDescription(cmdId)
if (titel === undefined) throw new Error(`No translation found for command ${cmdId}`)
return {
id: cmdId,
children: titel,
kind: "command",
group: desc?.category || "Commands",
showType: false,
onClick: async () => {
await ctx.commands!.executeCommand(cmdId, {})
}
}
})
}


// The host of the remote asset source server.
// The server must be running and accessible from the client.
const ASSET_SOURCE_HOST = 'http://localhost:3000';

function addDemoRemoteAssetSourcesPlugins(
cesdk: CreativeEditorSDK
): Promise<void>[] {
if (!ENABLE_DEMO_ASSET_SOURCES) return [];
return [
'/api/assets/v1/image-pexels',
'/api/assets/v1/image-unsplash',
'/api/assets/v1/video-pexels',
'/api/assets/v1/video-giphy'
].map(async (baseUrl) => {
await cesdk.unstable_addPlugin(
RemoteAssetSourcePlugin({
baseUrl: ASSET_SOURCE_HOST + baseUrl
})
);
});
}

// Helper function that automatically adds asset sources to the respective asset source panels:
// If the source starts with 'ly.img.audio', 'ly.img.image', or 'ly.img.video', it will be added to the respective panel.
// Should be used as a callback for the `entries` property of the `libraries.insert`/`libraries.replace` element in the UI configuration.

export const prepareAssetEntries = (defaultEntries: any, engine: any) => {
if (!engine) return defaultEntries;

const assetSourceIds = engine.asset.findAllSources() ?? [];
['ly.img.audio', 'ly.img.image', 'ly.img.video'].forEach((entryId) => {
const entry = defaultEntries.find((entry: any) => {
return entry.id === entryId;
});
if (entry) {
const assetSources = assetSourceIds
.filter((sourceId: any) => sourceId.startsWith(entryId + '.'))
.filter((sourceId: any) => !entry.sourceIds.includes(sourceId));
entry.sourceIds = [...entry.sourceIds, ...assetSources];
}
});
return defaultEntries;
};



export default App;
66 changes: 0 additions & 66 deletions examples/web/src/addPlugins.ts

This file was deleted.

Loading