@teamflojo/floimg-studio-ui 0.1.0

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.
@@ -0,0 +1,62 @@
1
+ interface CloudProvider {
2
+ apiKey: string;
3
+ enabled: boolean;
4
+ }
5
+ interface LocalProvider {
6
+ baseUrl: string;
7
+ enabled: boolean;
8
+ }
9
+ export interface AISettings {
10
+ openai?: CloudProvider;
11
+ anthropic?: CloudProvider;
12
+ gemini?: CloudProvider;
13
+ openrouter?: CloudProvider;
14
+ ollama?: LocalProvider;
15
+ lmstudio?: LocalProvider;
16
+ }
17
+ interface SettingsStore {
18
+ ai: AISettings;
19
+ setAIProvider: (provider: keyof AISettings, config: CloudProvider | LocalProvider) => void;
20
+ clearAIProvider: (provider: keyof AISettings) => void;
21
+ showSettings: boolean;
22
+ openSettings: () => void;
23
+ closeSettings: () => void;
24
+ getConfiguredProviders: () => {
25
+ openai?: {
26
+ apiKey: string;
27
+ };
28
+ anthropic?: {
29
+ apiKey: string;
30
+ };
31
+ gemini?: {
32
+ apiKey: string;
33
+ };
34
+ openrouter?: {
35
+ apiKey: string;
36
+ };
37
+ ollama?: {
38
+ baseUrl: string;
39
+ };
40
+ lmstudio?: {
41
+ baseUrl: string;
42
+ };
43
+ };
44
+ }
45
+ export declare const useSettingsStore: import('zustand').UseBoundStore<Omit<import('zustand').StoreApi<SettingsStore>, "setState" | "persist"> & {
46
+ setState(partial: SettingsStore | Partial<SettingsStore> | ((state: SettingsStore) => SettingsStore | Partial<SettingsStore>), replace?: false | undefined): unknown;
47
+ setState(state: SettingsStore | ((state: SettingsStore) => SettingsStore), replace: true): unknown;
48
+ persist: {
49
+ setOptions: (options: Partial<import('zustand/middleware').PersistOptions<SettingsStore, {
50
+ ai: AISettings;
51
+ }, unknown>>) => void;
52
+ clearStorage: () => void;
53
+ rehydrate: () => Promise<void> | void;
54
+ hasHydrated: () => boolean;
55
+ onHydrate: (fn: (state: SettingsStore) => void) => () => void;
56
+ onFinishHydration: (fn: (state: SettingsStore) => void) => () => void;
57
+ getOptions: () => Partial<import('zustand/middleware').PersistOptions<SettingsStore, {
58
+ ai: AISettings;
59
+ }, unknown>>;
60
+ };
61
+ }>;
62
+ export {};
@@ -0,0 +1,87 @@
1
+ import { Node, Edge, Connection } from 'reactflow';
2
+ import { GeneratorNodeData, TransformNodeData, SaveNodeData, InputNodeData, VisionNodeData, TextNodeData, NodeDefinition, GalleryTemplate } from '@teamflojo/floimg-studio-shared';
3
+
4
+ type NodeData = GeneratorNodeData | TransformNodeData | SaveNodeData | InputNodeData | VisionNodeData | TextNodeData;
5
+ type NodeExecutionStatus = "idle" | "running" | "completed" | "error";
6
+ interface DataOutput {
7
+ dataType: "text" | "json";
8
+ content: string;
9
+ parsed?: Record<string, unknown>;
10
+ }
11
+ export interface SavedWorkflow {
12
+ id: string;
13
+ name: string;
14
+ nodes: Node<NodeData>[];
15
+ edges: Edge[];
16
+ createdAt: number;
17
+ updatedAt: number;
18
+ templateId?: string;
19
+ }
20
+ interface ExecutionState {
21
+ status: "idle" | "running" | "completed" | "error";
22
+ imageIds: string[];
23
+ previews: Record<string, string>;
24
+ dataOutputs: Record<string, DataOutput>;
25
+ nodeStatus: Record<string, NodeExecutionStatus>;
26
+ error?: string;
27
+ }
28
+ interface WorkflowStore {
29
+ nodes: Node<NodeData>[];
30
+ edges: Edge[];
31
+ selectedNodeId: string | null;
32
+ currentTemplateId: string | null;
33
+ loadTemplate: (template: GalleryTemplate) => void;
34
+ clearWorkflow: () => void;
35
+ savedWorkflows: SavedWorkflow[];
36
+ activeWorkflowId: string | null;
37
+ activeWorkflowName: string;
38
+ hasUnsavedChanges: boolean;
39
+ showLibrary: boolean;
40
+ saveWorkflow: (name?: string) => string;
41
+ loadWorkflow: (id: string) => void;
42
+ deleteWorkflow: (id: string) => void;
43
+ renameWorkflow: (id: string, name: string) => void;
44
+ duplicateWorkflow: (id: string) => string;
45
+ newWorkflow: () => void;
46
+ setActiveWorkflowName: (name: string) => void;
47
+ toggleLibrary: () => void;
48
+ markDirty: () => void;
49
+ previewVisible: Record<string, boolean>;
50
+ togglePreview: (id: string) => void;
51
+ generators: NodeDefinition[];
52
+ transforms: NodeDefinition[];
53
+ setGenerators: (generators: NodeDefinition[]) => void;
54
+ setTransforms: (transforms: NodeDefinition[]) => void;
55
+ addNode: (definition: NodeDefinition, position: {
56
+ x: number;
57
+ y: number;
58
+ }) => void;
59
+ updateNodeData: (id: string, data: Partial<NodeData>) => void;
60
+ deleteNode: (id: string) => void;
61
+ setNodes: (nodes: Node<NodeData>[]) => void;
62
+ addEdge: (connection: Connection) => void;
63
+ deleteEdge: (id: string) => void;
64
+ setEdges: (edges: Edge[]) => void;
65
+ setSelectedNode: (id: string | null) => void;
66
+ execution: ExecutionState;
67
+ execute: () => Promise<void>;
68
+ exportToYaml: () => Promise<string>;
69
+ }
70
+ export declare const useWorkflowStore: import('zustand').UseBoundStore<Omit<import('zustand').StoreApi<WorkflowStore>, "setState" | "persist"> & {
71
+ setState(partial: WorkflowStore | Partial<WorkflowStore> | ((state: WorkflowStore) => WorkflowStore | Partial<WorkflowStore>), replace?: false | undefined): unknown;
72
+ setState(state: WorkflowStore | ((state: WorkflowStore) => WorkflowStore), replace: true): unknown;
73
+ persist: {
74
+ setOptions: (options: Partial<import('zustand/middleware').PersistOptions<WorkflowStore, {
75
+ savedWorkflows: SavedWorkflow[];
76
+ }, unknown>>) => void;
77
+ clearStorage: () => void;
78
+ rehydrate: () => Promise<void> | void;
79
+ hasHydrated: () => boolean;
80
+ onHydrate: (fn: (state: WorkflowStore) => void) => () => void;
81
+ onFinishHydration: (fn: (state: WorkflowStore) => void) => () => void;
82
+ getOptions: () => Partial<import('zustand/middleware').PersistOptions<WorkflowStore, {
83
+ savedWorkflows: SavedWorkflow[];
84
+ }, unknown>>;
85
+ };
86
+ }>;
87
+ export {};
@@ -0,0 +1 @@
1
+ .react-flow{direction:ltr}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;cursor:grab}.react-flow__pane.selection{cursor:pointer}.react-flow__pane.dragging{cursor:grabbing}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow .react-flow__edges{pointer-events:none;overflow:visible}.react-flow__edge-path,.react-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.react-flow__edge{pointer-events:visibleStroke;cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge:focus .react-flow__edge-path,.react-flow__edge:focus-visible .react-flow__edge-path{stroke:#555}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge-textbg{fill:#fff}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__connectionline{z-index:1001}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:grab}.react-flow__node.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background:#1a192b;border:1px solid white;border-radius:100%}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:-4px;transform:translate(-50%)}.react-flow__handle-top{left:50%;top:-4px;transform:translate(-50%)}.react-flow__handle-left{top:50%;left:-4px;transform:translateY(-50%)}.react-flow__handle-right{right:-4px;top:50%;transform:translateY(-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.center{left:50%;transform:translate(-50%)}.react-flow__attribution{font-size:10px;background:#ffffff80;padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-default,.react-flow__node-input,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:3px;width:150px;font-size:12px;color:#222;text-align:center;border-width:1px;border-style:solid;border-color:#1a192b;background-color:#fff}.react-flow__node-default.selectable:hover,.react-flow__node-input.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:0 1px 4px 1px #00000014}.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:0 0 0 .5px #1a192b}.react-flow__node-group{background-color:#f0f0f040}.react-flow__nodesselection-rect,.react-flow__selection{background:#0059dc14;border:1px dotted rgba(0,89,220,.8)}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls{box-shadow:0 0 2px 1px #00000014}.react-flow__controls-button{border:none;background:#fefefe;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;padding:5px}.react-flow__controls-button:hover{background:#f4f4f4}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__minimap{background-color:#fff}.react-flow__minimap svg{display:block}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:4px;height:4px;border:1px solid #fff;border-radius:1px;background-color:#3367d9;transform:translate(-50%,-50%)}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:#3367d9;border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}
@@ -0,0 +1,31 @@
1
+ import { GalleryTemplate } from '@teamflojo/floimg-studio-shared';
2
+
3
+ export declare const salesDashboard: GalleryTemplate;
4
+ export declare const userGrowth: GalleryTemplate;
5
+ export declare const apiFlowDiagram: GalleryTemplate;
6
+ export declare const systemArchitecture: GalleryTemplate;
7
+ export declare const gitWorkflow: GalleryTemplate;
8
+ export declare const websiteQR: GalleryTemplate;
9
+ export declare const wifiQR: GalleryTemplate;
10
+ export declare const chartWithWatermark: GalleryTemplate;
11
+ export declare const diagramToWebP: GalleryTemplate;
12
+ /**
13
+ * All available templates, organized by category
14
+ */
15
+ export declare const templates: GalleryTemplate[];
16
+ /**
17
+ * Get all unique categories
18
+ */
19
+ export declare function getCategories(): string[];
20
+ /**
21
+ * Get templates by category
22
+ */
23
+ export declare function getTemplatesByCategory(category: string): GalleryTemplate[];
24
+ /**
25
+ * Get a template by ID
26
+ */
27
+ export declare function getTemplateById(id: string): GalleryTemplate | undefined;
28
+ /**
29
+ * Search templates by query
30
+ */
31
+ export declare function searchTemplates(query: string): GalleryTemplate[];
@@ -0,0 +1,9 @@
1
+ import { Node, Edge } from 'reactflow';
2
+ import { GeneratorNodeData, TransformNodeData, SaveNodeData, InputNodeData, VisionNodeData, TextNodeData } from '@teamflojo/floimg-studio-shared';
3
+
4
+ type NodeData = GeneratorNodeData | TransformNodeData | SaveNodeData | InputNodeData | VisionNodeData | TextNodeData;
5
+ /**
6
+ * Generate JavaScript code from workflow nodes and edges
7
+ */
8
+ export declare function generateJavaScript(nodes: Node<NodeData>[], edges: Edge[]): string;
9
+ export {};
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@teamflojo/floimg-studio-ui",
3
+ "version": "0.1.0",
4
+ "description": "FloImg Studio React components for building visual workflow editors",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Flojo, Inc.",
8
+ "homepage": "https://floimg.com/studio",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/teamflojo/floimg.git",
12
+ "directory": "apps/studio/frontend"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/teamflojo/floimg/issues"
16
+ },
17
+ "keywords": [
18
+ "floimg",
19
+ "studio",
20
+ "workflow",
21
+ "image",
22
+ "editor",
23
+ "react",
24
+ "visual"
25
+ ],
26
+ "main": "./dist/index.js",
27
+ "module": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js"
33
+ },
34
+ "./styles.css": "./dist/styles.css"
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "README.md"
39
+ ],
40
+ "sideEffects": [
41
+ "*.css"
42
+ ],
43
+ "scripts": {
44
+ "dev": "vite 2>&1 | tee ../../logs/frontend.log",
45
+ "build": "tsc && vite build",
46
+ "build:lib": "vite build --mode lib",
47
+ "preview": "vite preview",
48
+ "typecheck": "tsc --noEmit"
49
+ },
50
+ "peerDependencies": {
51
+ "react": "^18.0.0 || ^19.0.0",
52
+ "react-dom": "^18.0.0 || ^19.0.0"
53
+ },
54
+ "dependencies": {
55
+ "@teamflojo/floimg-studio-shared": "workspace:*",
56
+ "@tanstack/react-query": "^5.90.12",
57
+ "reactflow": "^11.11.4",
58
+ "zustand": "^5.0.9"
59
+ },
60
+ "devDependencies": {
61
+ "@types/react": "^18.2.64",
62
+ "@types/react-dom": "^18.2.21",
63
+ "@vitejs/plugin-react": "^4.2.1",
64
+ "autoprefixer": "^10.4.18",
65
+ "postcss": "^8.4.35",
66
+ "tailwindcss": "^3.4.1",
67
+ "typescript": "^5.7.2",
68
+ "vite": "^5.1.6",
69
+ "vite-plugin-dts": "^3.7.3"
70
+ }
71
+ }