diff --git a/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/PrivacySettings.tsx b/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/PrivacySettings.tsx index 51c31173..c16e5f84 100644 --- a/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/PrivacySettings.tsx +++ b/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/PrivacySettings.tsx @@ -64,12 +64,10 @@ const PrivacySettings = () => {

- Anonymous Usage Tracking + Usage analytics

- When enabled, Presenton collects anonymous usage data to help us - understand how the app is used and improve your experience. No - personal information or presentation content is ever collected. + Share anonymous usage data to help us improve Presenton. No personal information or presentation content is collected.

@@ -78,12 +76,12 @@ const PrivacySettings = () => { htmlFor="tracking-toggle" className="text-sm font-medium text-[#191919] cursor-pointer select-none block" > - {trackingEnabled ? "Tracking Enabled" : "Tracking Disabled"} + Share anonymous usage data

{trackingEnabled - ? "Anonymous usage data is being sent." - : "No usage data is being collected."} + ? "Anonymous usage data is being shared." + : "Anonymous usage data is not being shared"}

diff --git a/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/SettingSideBar.tsx b/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/SettingSideBar.tsx index d18db184..f13d5618 100644 --- a/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/SettingSideBar.tsx +++ b/electron/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/SettingSideBar.tsx @@ -9,31 +9,31 @@ const SettingSideBar = ({ mode, setMode, selectedProvider, setSelectedProvider } const textProviderIcon = LLM_PROVIDERS[llm_config.LLM as keyof typeof LLM_PROVIDERS]?.icon const imageProviderIcon = IMAGE_PROVIDERS[llm_config.IMAGE_PROVIDER as keyof typeof IMAGE_PROVIDERS]?.icon || '/providers/pexel.png' return ( -
+

FILTER BY:

Select Mode

-
- 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 = () => { presenton

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.

{
)} - + 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")}

- - {isPro === true ? ( - - ) : ( - - )} - {planLabel} - +
{email && username && (

{email}

diff --git a/electron/servers/nextjs/public/providers/custom.svg b/electron/servers/nextjs/public/providers/custom.svg new file mode 100644 index 00000000..aef5d834 --- /dev/null +++ b/electron/servers/nextjs/public/providers/custom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/electron/servers/nextjs/utils/providerConstants.ts b/electron/servers/nextjs/utils/providerConstants.ts index 4dfc6c4b..e946212c 100644 --- a/electron/servers/nextjs/utils/providerConstants.ts +++ b/electron/servers/nextjs/utils/providerConstants.ts @@ -130,7 +130,7 @@ export const LLM_PROVIDERS: Record = { value: "custom", label: "Custom", description: "OpenAI-compatible LLM", - icon: "/icons/custom.png", + icon: "/providers/custom.svg", }, }; diff --git a/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx b/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx index 320b3ada..d2d3ac2a 100644 --- a/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx +++ b/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx @@ -224,7 +224,7 @@ const TextProvider = ({

Text Generation Settings

- Choosing where text contets come from + Choosing where text content comes from

diff --git a/servers/nextjs/components/OnBoarding/PresentonMode.tsx b/servers/nextjs/components/OnBoarding/PresentonMode.tsx index 30c7df5a..51bc3a21 100644 --- a/servers/nextjs/components/OnBoarding/PresentonMode.tsx +++ b/servers/nextjs/components/OnBoarding/PresentonMode.tsx @@ -341,7 +341,7 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:

Text Generation Settings

- Choosing where text contets come from + Choosing where text content comes from