diff --git a/docs-site/astro.config.mjs b/docs-site/astro.config.mjs index 412421f1..bedef463 100644 --- a/docs-site/astro.config.mjs +++ b/docs-site/astro.config.mjs @@ -6,7 +6,7 @@ export default defineConfig({ site: 'https://docs.openflowkit.com', integrations: [ starlight({ - title: 'OpenFlowKit Docs', + title: 'OpenFlowKit | Free Local-First AI Diagramming for Builders', description: 'Documentation for OpenFlowKit — the local-first, AI-powered diagramming tool.', favicon: '/favicon.svg', logo: { diff --git a/docs-site/src/pages/index.astro b/docs-site/src/pages/index.astro index c9ce91a4..10815e3e 100644 --- a/docs-site/src/pages/index.astro +++ b/docs-site/src/pages/index.astro @@ -64,7 +64,7 @@ const referenceLinks = [ - OpenFlowKit — Free Open-Source Diagram Tool for Developers + OpenFlowKit | Free Local-First AI Diagramming for Builders - + - + + - + - + + diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index e86239ec..0c4630d9 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -387,7 +387,7 @@ "exportFormats": "Export to SVG, PNG, JPG", "figmaExport": "Figma Export", "mermaidSupport": "Mermaid.js Support", - "aiGeneration": "AI diagram generation (bring your own API key)" + "aiGeneration": "AI diagram generation (BYOK)" }, "supportDevelopment": "Support development on GitHub" }, @@ -1211,4 +1211,4 @@ "closeTab": "Close Tab", "newFlowTab": "New Flow Tab" } -} +} \ No newline at end of file diff --git a/src/components/FlowEditor.tsx b/src/components/FlowEditor.tsx index 827bfad9..fcbedb9e 100644 --- a/src/components/FlowEditor.tsx +++ b/src/components/FlowEditor.tsx @@ -7,7 +7,6 @@ import { ArchitectureLintProvider } from '@/context/ArchitectureLintContext'; import { useCinematicExportState } from '@/context/CinematicExportContext'; import { DiagramDiffProvider } from '@/context/DiagramDiffContext'; import { ShareEmbedModal } from '@/components/ShareEmbedModal'; -import { CinematicExportSurface } from '@/components/export/CinematicExportSurface'; const CINEMATIC_EXPORT_BACKGROUND = 'radial-gradient(circle at top, rgba(59,130,246,0.14), transparent 42%), linear-gradient(180deg, #f8fbff 0%, #eef5ff 52%, #f8fafc 100%)'; @@ -29,7 +28,6 @@ export function FlowEditor({ onGoHome }: FlowEditorProps) { recordHistory, isSelectMode, reactFlowWrapper, - cinematicExportSurfaceRef, fileInputRef, onFileImport, shareViewerUrl, @@ -88,11 +86,6 @@ export function FlowEditor({ onGoHome }: FlowEditorProps) { {shareViewerUrl && ( )} - diff --git a/src/components/StudioAIPanel.tsx b/src/components/StudioAIPanel.tsx index 59a0d1c6..fc3666b8 100644 --- a/src/components/StudioAIPanel.tsx +++ b/src/components/StudioAIPanel.tsx @@ -26,10 +26,9 @@ const EMPTY_CANVAS_EXAMPLES: AIStudioExample[] = [ ]; const ITERATION_EXAMPLES: AIStudioExample[] = [ - { label: 'Add Database', icon: Database, prompt: 'Add a PostgreSQL database to the architecture' }, - { label: 'Add Server', icon: Server, prompt: 'Add a backend Node.js server service' }, - { label: 'Add Cloud Infrastructure', icon: Cloud, prompt: 'Deploy the main application to AWS' }, - { label: 'Add Load Balancer', icon: Network, prompt: 'Add a load balancer in front of the application' }, + { label: 'Database', icon: Database, prompt: 'Add a PostgreSQL database to the architecture' }, + { label: 'Server', icon: Server, prompt: 'Add a backend Node.js server service' }, + { label: 'Deploy to AWS', icon: Cloud, prompt: 'Deploy the main application to AWS' }, ]; const EXAMPLE_ICON_COLORS = [ @@ -178,12 +177,14 @@ export function StudioAIPanel({ }, [initialPrompt, onInitialPromptConsumed, setPrompt]); const hasHistory = chatMessages.length > 0; + const isCanvasEmpty = nodeCount === 0; const effectiveGenerationMode: AIGenerationMode = nodeCount === 0 ? 'create' : generationMode; - const examplePrompts = nodeCount === 0 ? EMPTY_CANVAS_EXAMPLES : ITERATION_EXAMPLES; - const sendButtonLabel = effectiveGenerationMode === 'edit' && nodeCount > 0 + const examplePrompts = isCanvasEmpty ? EMPTY_CANVAS_EXAMPLES : ITERATION_EXAMPLES; + const isEditMode = effectiveGenerationMode === 'edit' && !isCanvasEmpty; + const sendButtonLabel = isEditMode ? 'Apply AI edit' : 'Generate diagram'; - const sendButtonIcon = generationMode === 'edit' && nodeCount > 0 ? : ; + const sendButtonIcon = isEditMode ? : ; async function submitPrompt(promptText?: string): Promise { const resolvedPrompt = promptText ?? prompt; @@ -204,7 +205,7 @@ export function StudioAIPanel({ void submitPrompt(); } - const isInputEmpty = (!prompt.trim() && !selectedImage); + const isInputEmpty = !prompt.trim() && !selectedImage; return (
@@ -267,13 +268,13 @@ export function StudioAIPanel({

{FLOWPILOT_NAME}

- {nodeCount === 0 + {isCanvasEmpty ? `Describe the diagram you want and ${FLOWPILOT_NAME} will draft the first graph for you.` : `Describe the changes you want and ${FLOWPILOT_NAME} will update the graph for you.`}

{aiReadiness.canGenerate && ( -
+
{examplePrompts.map((skill, index) => { const Icon = skill.icon; return ( @@ -283,10 +284,12 @@ export function StudioAIPanel({ setPrompt(skill.prompt); void submitPrompt(skill.prompt); }} - className="flex items-center gap-2 rounded-full border border-slate-200 bg-white px-5 py-2.5 text-[13px] font-medium text-slate-700 shadow-sm transition-all duration-200 hover:border-[var(--brand-primary-200)] hover:text-[var(--brand-primary)] hover:shadow-md active:scale-95" + className="inline-flex min-h-9 items-center gap-2 rounded-full border border-white bg-white px-3 py-2 text-left text-[12px] font-semibold leading-none text-slate-700 shadow-sm shadow-slate-200/70 ring-1 ring-slate-200/70 transition-all duration-200 hover:-translate-y-px hover:border-[var(--brand-primary-100)] hover:text-[var(--brand-primary)] hover:shadow-md active:scale-95" > - - {skill.label} + + + + {skill.label} ); })} diff --git a/src/components/WelcomeModal.tsx b/src/components/WelcomeModal.tsx index bb88a56a..f6d7e457 100644 --- a/src/components/WelcomeModal.tsx +++ b/src/components/WelcomeModal.tsx @@ -104,16 +104,7 @@ export function WelcomeModal({ onOpenTemplates, onPromptWithAI, onImport, onBlan
-
- -
+

Welcome to OpenFlowKit

Pick the fastest way to get to a real developer diagram: template, import, prompt, or blank canvas. diff --git a/src/components/app/MobileWorkspaceGate.tsx b/src/components/app/MobileWorkspaceGate.tsx index 59dc60e3..b0c87039 100644 --- a/src/components/app/MobileWorkspaceGate.tsx +++ b/src/components/app/MobileWorkspaceGate.tsx @@ -18,9 +18,7 @@ export function MobileWorkspaceGate({ <>

-
- -
+
diff --git a/src/components/custom-edge/CustomEdgeWrapper.tsx b/src/components/custom-edge/CustomEdgeWrapper.tsx index a9f83b38..a1a8295b 100644 --- a/src/components/custom-edge/CustomEdgeWrapper.tsx +++ b/src/components/custom-edge/CustomEdgeWrapper.tsx @@ -425,7 +425,7 @@ export function CustomEdgeWrapper({ onDoubleClick={(e) => { e.stopPropagation(); beginLabelEdit(); }} className={ visualQualityV2Enabled - ? `px-2 py-0.5 rounded-full border shadow-sm text-[11px] font-medium select-none flow-lod-secondary flow-lod-shadow transition-all ${cinematicActive ? 'bg-white/96 border-slate-200/90 text-slate-600 shadow-[0_6px_18px_rgba(15,23,42,0.08)]' : 'bg-white/90 border-slate-200 text-slate-500 hover:border-indigo-300 hover:text-slate-700 hover:shadow active:ring-2 active:ring-indigo-400'}` + ? `whitespace-nowrap px-2 py-0.5 rounded-full border shadow-sm text-[11px] font-medium select-none flow-lod-secondary flow-lod-shadow transition-all ${cinematicActive ? 'bg-white/96 border-slate-200/90 text-slate-600 shadow-[0_6px_18px_rgba(15,23,42,0.08)]' : 'bg-white/90 border-slate-200 text-slate-500 hover:border-indigo-300 hover:text-slate-700 hover:shadow active:ring-2 active:ring-indigo-400'}` : 'bg-white px-2 py-0.5 rounded border border-slate-200 shadow-sm text-[11px] font-medium text-slate-500 hover:ring-2 hover:ring-indigo-500/20 active:ring-indigo-500 select-none flow-lod-secondary flow-lod-shadow' } > diff --git a/src/components/export/CinematicExportSurface.tsx b/src/components/export/CinematicExportSurface.tsx deleted file mode 100644 index b603d9d7..00000000 --- a/src/components/export/CinematicExportSurface.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React, { forwardRef } from 'react'; -import { Background, BackgroundVariant, ReactFlow, ReactFlowProvider } from '@/lib/reactflowCompat'; -import type { FlowEdge, FlowNode } from '@/lib/types'; -import { useCinematicExportSurfaceConfig } from '@/context/CinematicExportContext'; -import { flowCanvasEdgeTypes, flowCanvasNodeTypes } from '@/components/flow-canvas/flowCanvasTypes'; - -const CINEMATIC_EXPORT_SURFACE_BACKGROUND = - 'radial-gradient(circle at top, rgba(59,130,246,0.14), transparent 42%), linear-gradient(180deg, #f8fbff 0%, #eef5ff 52%, #f8fafc 100%)'; -const CINEMATIC_EXPORT_SURFACE_STYLE = { - position: 'fixed', - top: 0, - left: 0, - transform: 'translate(-20000px, 0)', - overflow: 'hidden', - pointerEvents: 'none', - zIndex: -1, - background: CINEMATIC_EXPORT_SURFACE_BACKGROUND, -} as const; - -interface CinematicExportSurfaceProps { - nodes: FlowNode[]; - edges: FlowEdge[]; -} - -function CinematicExportSurfaceInner( - { nodes, edges }: CinematicExportSurfaceProps, - ref: React.ForwardedRef, -): React.ReactElement | null { - const surfaceConfig = useCinematicExportSurfaceConfig(); - - if (!surfaceConfig) { - return null; - } - - return ( - - ); -} - -export const CinematicExportSurface = forwardRef(CinematicExportSurfaceInner); -CinematicExportSurface.displayName = 'CinematicExportSurface'; diff --git a/src/components/flow-editor/useFlowEditorScreenModel.ts b/src/components/flow-editor/useFlowEditorScreenModel.ts index fc7f177b..53f032de 100644 --- a/src/components/flow-editor/useFlowEditorScreenModel.ts +++ b/src/components/flow-editor/useFlowEditorScreenModel.ts @@ -90,7 +90,7 @@ export function useFlowEditorScreenModel({ onGoHome }: UseFlowEditorScreenModelP onFileImport, } = useFlowExport(screenState.recordHistory, screenState.reactFlowWrapper, { stopPlayback, - }, screenState.cinematicExportSurfaceRef); + }); const { collaborationTopNavState, @@ -309,7 +309,6 @@ export function useFlowEditorScreenModel({ onGoHome }: UseFlowEditorScreenModelP recordHistory: screenState.recordHistory, isSelectMode: screenState.isSelectMode, reactFlowWrapper: screenState.reactFlowWrapper, - cinematicExportSurfaceRef: screenState.cinematicExportSurfaceRef, fileInputRef, onFileImport, shareViewerUrl, diff --git a/src/components/flow-editor/useFlowEditorScreenState.ts b/src/components/flow-editor/useFlowEditorScreenState.ts index 255db3fe..92c6dbe1 100644 --- a/src/components/flow-editor/useFlowEditorScreenState.ts +++ b/src/components/flow-editor/useFlowEditorScreenState.ts @@ -41,7 +41,6 @@ export function useFlowEditorScreenState() { const snapshotsState = useSnapshots(); const uiState = useFlowEditorUIState(); const reactFlowWrapper = useRef(null); - const cinematicExportSurfaceRef = useRef(null); const reactFlowState = useReactFlow(); const historyState = useFlowHistory(); @@ -60,7 +59,6 @@ export function useFlowEditorScreenState() { ...snapshotsState, ...uiState, reactFlowWrapper, - cinematicExportSurfaceRef, ...reactFlowState, ...historyState, }; diff --git a/src/components/home/HomeSidebar.tsx b/src/components/home/HomeSidebar.tsx index 94b82d8a..d216a815 100644 --- a/src/components/home/HomeSidebar.tsx +++ b/src/components/home/HomeSidebar.tsx @@ -20,9 +20,7 @@ export function HomeSidebar({ return (