Select Mode
-
setMode('presenton')}
style={{
background: mode === 'presenton' ? '#F4F3FF' : 'transparent',
color: mode === 'presenton' ? '#5146E5' : '#3A3A3A'
}}
- >Presenton
+ >Template Based
-
- Nanobanana
+ Image Based
Coming soon
diff --git a/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx b/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx
index 89d351d5..11860386 100644
--- a/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx
+++ b/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx
@@ -229,7 +229,7 @@ const TextProvider = ({
Text Generation Settings
- Choosing where text contets come from
+ Choosing where text content comes from
diff --git a/electron/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationHeader.tsx b/electron/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationHeader.tsx
index fdda8bf2..431b0978 100644
--- a/electron/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationHeader.tsx
+++ b/electron/servers/nextjs/app/(presentation-generator)/presentation/components/PresentationHeader.tsx
@@ -432,7 +432,7 @@ const PresentationHeader = ({
trackEvent(MixpanelEvent.Navigation, { from: pathname, to });
router.push(to);
}}
- disabled={!presentationData?.slides || presentationData?.slides.length === 0} className="cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed group">
+ disabled={isStreaming || !presentationData?.slides || presentationData?.slides.length === 0} className="cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed group">
@@ -444,7 +444,7 @@ const PresentationHeader = ({
style={{
background: "linear-gradient(270deg, #D5CAFC 2.4%, #E3D2EB 27.88%, #F4DCD3 69.23%, #FDE4C2 100%)",
}}
- disabled={isExporting}
+ disabled={isExporting || isStreaming === true}
>
{isExporting ?
: "Export"}
diff --git a/electron/servers/nextjs/app/(presentation-generator)/upload/page.tsx b/electron/servers/nextjs/app/(presentation-generator)/upload/page.tsx
index b935c01a..188f47c6 100644
--- a/electron/servers/nextjs/app/(presentation-generator)/upload/page.tsx
+++ b/electron/servers/nextjs/app/(presentation-generator)/upload/page.tsx
@@ -47,7 +47,7 @@ const page = () => {
- AI Presentation
+ Generate Presentation
Choose a design, set preferences, and generate polished slides.
diff --git a/electron/servers/nextjs/components/CodexConfig.tsx b/electron/servers/nextjs/components/CodexConfig.tsx
index 2ecc0dfb..9ae4a3b8 100644
--- a/electron/servers/nextjs/components/CodexConfig.tsx
+++ b/electron/servers/nextjs/components/CodexConfig.tsx
@@ -323,20 +323,7 @@ export default function CodexConfig({
{username || email || (accountId ? `Account ${accountId}` : "ChatGPT Account")}
-
- {isPro === true ? (
-
- ) : (
-
- )}
- {planLabel}
-
+
{email && username && (
{email}
diff --git a/electron/servers/nextjs/components/Home.tsx b/electron/servers/nextjs/components/Home.tsx
index b03196e1..748f90d6 100644
--- a/electron/servers/nextjs/components/Home.tsx
+++ b/electron/servers/nextjs/components/Home.tsx
@@ -1,19 +1,8 @@
"use client";
-import { useState, useEffect, useMemo } from "react";
+import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
-import { toast } from "sonner";
-import { Loader2, Download, CheckCircle } from "lucide-react";
import { useSelector } from "react-redux";
import { RootState } from "@/store/store";
-import { handleSaveLLMConfig } from "@/utils/storeHelpers";
-import LLMProviderSelection from "./LLMSelection";
-import {
- checkIfSelectedOllamaModelIsPulled,
- pullOllamaModel,
-} from "@/utils/providerUtils";
-import { LLMConfig } from "@/types/llm_config";
-import { trackEvent, MixpanelEvent } from "@/utils/mixpanel";
-import { usePathname } from "next/navigation";
import OnBoardingSlidebar from "./OnBoarding/OnBoardingSlidebar";
import OnBoardingHeader from "./OnBoarding/OnBoardingHeader";
import ModeSelectStep from "./OnBoarding/ModeSelectStep";
@@ -21,130 +10,22 @@ import PresentonMode from "./OnBoarding/PresentonMode";
import GenerationWithImage from "./OnBoarding/GenerationWithImage";
import FinalStep from "./OnBoarding/FinalStep";
-// Button state interface
-interface ButtonState {
- isLoading: boolean;
- isDisabled: boolean;
- text: string;
- showProgress: boolean;
- progressPercentage?: number;
- status?: string;
-}
-
-const getTaperedSideOffset = (offset: number, top: number) => {
- const taperMultiplier = Math.max(0.72, 1.85 - top * 0.012);
- return Math.min(29, Number((offset * taperMultiplier).toFixed(2)));
-};
export default function Home() {
const router = useRouter();
- const pathname = usePathname();
const [step, setStep] = useState
(1)
const [selectedMode, setSelectedMode] = useState("presenton")
const config = useSelector((state: RootState) => state.userConfig);
- const [llmConfig, setLlmConfig] = useState(config.llm_config);
- const [downloadingModel, setDownloadingModel] = useState<{
- name: string;
- size: number | null;
- downloaded: number | null;
- status: string;
- done: boolean;
- } | null>(null);
- const [showDownloadModal, setShowDownloadModal] = useState(false);
- const [buttonState, setButtonState] = useState({
- isLoading: false,
- isDisabled: false,
- text: "Save Configuration",
- showProgress: false
- });
const canChangeKeys = config.can_change_keys;
- const downloadProgress = useMemo(() => {
- if (downloadingModel && downloadingModel.downloaded !== null && downloadingModel.size !== null) {
- return Math.round((downloadingModel.downloaded / downloadingModel.size) * 100);
- }
- return 0;
- }, [downloadingModel?.downloaded, downloadingModel?.size]);
-
- const handleSaveConfig = async () => {
- trackEvent(MixpanelEvent.Home_SaveConfiguration_Button_Clicked, { pathname });
- try {
- setButtonState(prev => ({
- ...prev,
- isLoading: true,
- isDisabled: true,
- text: "Saving Configuration..."
- }));
- // API: save config
- trackEvent(MixpanelEvent.Home_SaveConfiguration_API_Call);
- // API CALL: save config
- await handleSaveLLMConfig(llmConfig);
-
- if (llmConfig.LLM === "ollama" && llmConfig.OLLAMA_MODEL) {
- // API: check model pulled
- trackEvent(MixpanelEvent.Home_CheckOllamaModelPulled_API_Call);
- const isPulled = await checkIfSelectedOllamaModelIsPulled(llmConfig.OLLAMA_MODEL);
- if (!isPulled) {
- setShowDownloadModal(true);
- // API: download model
- trackEvent(MixpanelEvent.Home_DownloadOllamaModel_API_Call);
- await handleModelDownload();
- }
- }
- toast.info("Configuration saved successfully");
- setButtonState(prev => ({
- ...prev,
- isLoading: false,
- isDisabled: false,
- text: "Save Configuration"
- }));
- // Track navigation from -> to
- trackEvent(MixpanelEvent.Navigation, { from: pathname, to: "/upload" });
- router.push("/upload");
- } catch (error) {
- toast.info(error instanceof Error ? error.message : "Failed to save configuration");
- setButtonState(prev => ({
- ...prev,
- isLoading: false,
- isDisabled: false,
- text: "Save Configuration"
- }));
- }
- };
-
- const handleModelDownload = async () => {
- try {
- await pullOllamaModel(llmConfig.OLLAMA_MODEL!, setDownloadingModel);
- }
- finally {
- setDownloadingModel(null);
- setShowDownloadModal(false);
- }
- };
- useEffect(() => {
- if (downloadingModel && downloadingModel.downloaded !== null && downloadingModel.size !== null) {
- const percentage = Math.round(((downloadingModel.downloaded / downloadingModel.size) * 100));
- setButtonState({
- isLoading: true,
- isDisabled: true,
- text: `Downloading Model (${percentage}%)`,
- showProgress: true,
- progressPercentage: percentage,
- status: downloadingModel.status
- });
- }
- if (downloadingModel && downloadingModel.done) {
- setTimeout(() => {
- setShowDownloadModal(false);
- setDownloadingModel(null);
- toast.info("Model downloaded successfully!");
- }, 2000);
- }
- }, [downloadingModel]);
+
+
+
+
useEffect(() => {
if (!canChangeKeys) {
diff --git a/electron/servers/nextjs/components/OnBoarding/FinalStep.tsx b/electron/servers/nextjs/components/OnBoarding/FinalStep.tsx
index e396a1da..5a445b61 100644
--- a/electron/servers/nextjs/components/OnBoarding/FinalStep.tsx
+++ b/electron/servers/nextjs/components/OnBoarding/FinalStep.tsx
@@ -86,13 +86,13 @@ const FinalStep = () => {
Welcome on board!
- Your AI workspace is ready. Let's create your first presentation.
+ You’re all set. Let’s create your first presentation.
{trackingEnabled !== null && (
-
Anonymous Tracking
-
Help improve Presenton with anonymous usage data.
+
Usage analytics
+
Help improve Presenton by sharing anonymous usage data.
{
)}
- My First Presentation
+ My First Presentation 🚀
Celebrate again!
diff --git a/electron/servers/nextjs/components/OnBoarding/ModeSelectStep.tsx b/electron/servers/nextjs/components/OnBoarding/ModeSelectStep.tsx
index d04cbdb8..f4c1bf37 100644
--- a/electron/servers/nextjs/components/OnBoarding/ModeSelectStep.tsx
+++ b/electron/servers/nextjs/components/OnBoarding/ModeSelectStep.tsx
@@ -6,8 +6,8 @@ const ModeSelectStep = ({ selectedMode, setStep, setSelectedMode }: { selectedMo
-
Let’s set up your AI workspace
-
First, choose the intelligence behind your presentation generation.
+
Choose how you want to generate presentations
+
Pick a generation mode first. You’ll connect your model providers in the next step.
{
@@ -21,17 +21,17 @@ const ModeSelectStep = ({ selectedMode, setStep, setSelectedMode }: { selectedMo
-
Presenton
-
PPTX
+
Template Presentation Mode
+
PPTX Export
-
Optimized for fast, structured slide generation.
+
Best for structured decks, editing, and PPTX export. Requires text and image providers.
-
Coming soon
+
Coming soon
@@ -40,10 +40,10 @@ const ModeSelectStep = ({ selectedMode, setStep, setSelectedMode }: { selectedMo
-
Generate with Image Model
-
+
Image Slides Mode
+
No PPTX Export
-
Instantly generate presentation slides as images.
+
Best for visual slide generation from image models. No PPTX export.
@@ -56,7 +56,7 @@ const ModeSelectStep = ({ selectedMode, setStep, setSelectedMode }: { selectedMo
setStep(2);
}}
className='border font-syne border-[#EDEEEF] bg-[#7C51F8] rounded-[58px] px-5 py-2.5 text-white text-xs font-semibold'>
- Start With {selectedMode === "presenton" ? "Presenton" : "Image Model"}
+ Continue to providers
diff --git a/electron/servers/nextjs/components/OnBoarding/PresentonMode.tsx b/electron/servers/nextjs/components/OnBoarding/PresentonMode.tsx
index 8ef5ca9c..95a98ac5 100644
--- a/electron/servers/nextjs/components/OnBoarding/PresentonMode.tsx
+++ b/electron/servers/nextjs/components/OnBoarding/PresentonMode.tsx
@@ -353,7 +353,7 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
Text Generation Settings
- Choosing where text contets come from
+ Choosing where text content comes from
diff --git a/electron/servers/nextjs/components/SettingCodex.tsx b/electron/servers/nextjs/components/SettingCodex.tsx
index 5533fe85..b0e7b705 100644
--- a/electron/servers/nextjs/components/SettingCodex.tsx
+++ b/electron/servers/nextjs/components/SettingCodex.tsx
@@ -297,20 +297,7 @@ export default function CodexConfig({
{username || email || (accountId ? `Account ${accountId}` : "ChatGPT Account")}