diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index ba93367803..ee542e2dd8 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -5062,7 +5062,7 @@ }, "welcomeSlide": { "title": "Welcome to Stirling", - "body": "Stirling PDF is now ready for teams of all sizes.
This update includes a new layout, powerful new admin capabilities, and our most requested feature - Edit Text." + "body": "Stirling PDF is now ready for teams of all sizes. This update includes a new layout, powerful new admin capabilities, and our most requested feature - Edit Text." }, "allTools": "This is the Tools panel, where you can browse and select from all available PDF tools.", "selectCropTool": "Let's select the Crop tool to demonstrate how to use one of the tools.", @@ -5096,6 +5096,17 @@ "overLimitBody": "Our licensing permits up to {{freeTierLimit}} users for free per server. You have {{overLimitUserCopy}} Stirling users. To continue uninterrupted, upgrade to the Stirling Server plan - unlimited seats, PDF text editing, and full admin control for $99/server/mo.", "freeBody": "Our Open-Core licensing permits up to {{freeTierLimit}} users for free per server. To scale uninterrupted and get early access to our new PDF text editing tool, we recommend the Stirling Server plan - full editing and unlimited seats for $99/server/mo." }, + "desktopInstall": { + "title": "Download", + "titleWithOs": "Download for {{osLabel}}", + "body": "Stirling works best as a desktop app. You can use it offline, access documents faster, and make edits locally on your computer." + }, + "planOverview": { + "adminTitle": "Admin Overview", + "userTitle": "Plan Overview", + "adminBody": "As an admin, you can manage users, configure settings, and monitor server health. The first {{freeTierLimit}} people on your server get to use Stirling free of charge.", + "userBody": "Invite teammates, assign roles, and keep your documents organized in one secure workspace. Enable login mode whenever you're ready to grow beyond solo use." + }, "securityCheck": { "message": "The application has undergone significant changes recently. Your server admin's attention may be required. Please confirm your role to continue." } diff --git a/frontend/public/locales/en-US/translation.json b/frontend/public/locales/en-US/translation.json index 9f62ceb95a..ceb0cb2adf 100644 --- a/frontend/public/locales/en-US/translation.json +++ b/frontend/public/locales/en-US/translation.json @@ -4872,7 +4872,7 @@ }, "welcomeSlide": { "title": "Welcome to Stirling", - "body": "Stirling PDF is now ready for teams of all sizes.
This update includes a new layout, powerful new admin capabilities, and our most requested feature - Edit Text." + "body": "Stirling PDF is now ready for teams of all sizes. This update includes a new layout, powerful new admin capabilities, and our most requested feature - Edit Text." }, "allTools": "This is the Tools panel, where you can browse and select from all available PDF tools.", "selectCropTool": "Let's select the Crop tool to demonstrate how to use one of the tools.", @@ -4906,6 +4906,17 @@ "overLimitBody": "Our licensing permits up to {{freeTierLimit}} users for free per server. You have {{overLimitUserCopy}} Stirling users. To continue uninterrupted, upgrade to the Stirling Server plan - unlimited seats, PDF text editing, and full admin control for $99/server/mo.", "freeBody": "Our Open-Core licensing permits up to {{freeTierLimit}} users for free per server. To scale uninterrupted and get early access to our new PDF text editing tool, we recommend the Stirling Server plan - full editing and unlimited seats for $99/server/mo." }, + "desktopInstall": { + "title": "Download", + "titleWithOs": "Download for {{osLabel}}", + "body": "Stirling works best as a desktop app. You can use it offline, access documents faster, and make edits locally on your computer." + }, + "planOverview": { + "adminTitle": "Admin Overview", + "userTitle": "Plan Overview", + "adminBody": "As an admin, you can manage users, configure settings, and monitor server health. The first {{freeTierLimit}} people on your server get to use Stirling free of charge.", + "userBody": "Invite teammates, assign roles, and keep your documents organized in one secure workspace. Enable login mode whenever you're ready to grow beyond solo use." + }, "securityCheck": { "message": "The application has undergone significant changes recently. Your server admin's attention may be required. Please confirm your role to continue." } diff --git a/frontend/src/core/components/onboarding/InitialOnboardingModal/renderButtons.tsx b/frontend/src/core/components/onboarding/InitialOnboardingModal/renderButtons.tsx index 8b41114a3d..428a27df1e 100644 --- a/frontend/src/core/components/onboarding/InitialOnboardingModal/renderButtons.tsx +++ b/frontend/src/core/components/onboarding/InitialOnboardingModal/renderButtons.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Button, Group, ActionIcon } from '@mantine/core'; import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; import { ButtonDefinition, type FlowState } from '@app/components/onboarding/onboardingFlowConfig'; -import type { LicenseNotice } from '@app/components/onboarding/slides/types'; +import type { LicenseNotice } from '@app/types/types'; import type { ButtonAction } from '@app/components/onboarding/onboardingFlowConfig'; interface RenderButtonsProps { diff --git a/frontend/src/core/components/onboarding/InitialOnboardingModal/types.ts b/frontend/src/core/components/onboarding/InitialOnboardingModal/types.ts index 589e667a0d..d8bc96a1cf 100644 --- a/frontend/src/core/components/onboarding/InitialOnboardingModal/types.ts +++ b/frontend/src/core/components/onboarding/InitialOnboardingModal/types.ts @@ -1,4 +1,4 @@ -import type { LicenseNotice } from '@app/components/onboarding/slides/types'; +import type { LicenseNotice } from '@app/types/types'; export interface InitialOnboardingModalProps { opened: boolean; diff --git a/frontend/src/core/components/onboarding/InitialOnboardingModal/useInitialOnboardingState.ts b/frontend/src/core/components/onboarding/InitialOnboardingModal/useInitialOnboardingState.ts index 3dd53ddd8c..c57b0990b0 100644 --- a/frontend/src/core/components/onboarding/InitialOnboardingModal/useInitialOnboardingState.ts +++ b/frontend/src/core/components/onboarding/InitialOnboardingModal/useInitialOnboardingState.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState, useRef } from 'react'; import { usePreferences } from '@app/contexts/PreferencesContext'; import { useOnboarding } from '@app/contexts/OnboardingContext'; import { useOs } from '@app/hooks/useOs'; @@ -9,7 +9,7 @@ import { type FlowState, type SlideId, } from '@app/components/onboarding/onboardingFlowConfig'; -import type { LicenseNotice } from '@app/components/onboarding/slides/types'; +import type { LicenseNotice } from '@app/types/types'; import { resolveFlow } from './flowResolver'; import { useServerExperience } from '@app/hooks/useServerExperience'; import { DEFAULT_STATE, type InitialOnboardingModalProps, type OnboardingState } from './types'; @@ -45,6 +45,7 @@ export function useInitialOnboardingState({ } = useServerExperience(); const osType = useOs(); const navigate = useNavigate(); + const selectedDownloadUrlRef = useRef(''); const [state, setState] = useState(DEFAULT_STATE); @@ -105,7 +106,7 @@ export function useInitialOnboardingState({ case 'windows': return { label: 'Windows', url: 'https://files.stirlingpdf.com/win-installer.exe' }; case 'mac-apple': - return { label: 'Mac', url: 'https://files.stirlingpdf.com/mac-installer.dmg' }; + return { label: 'Mac (Apple Silicon)', url: 'https://files.stirlingpdf.com/mac-installer.dmg' }; case 'mac-intel': return { label: 'Mac (Intel)', url: 'https://files.stirlingpdf.com/mac-x86_64-installer.dmg' }; case 'linux-x64': @@ -116,6 +117,16 @@ export function useInitialOnboardingState({ } }, [osType]); + const osOptions = useMemo(() => { + const options = [ + { label: 'Windows', url: 'https://files.stirlingpdf.com/win-installer.exe', value: 'windows' }, + { label: 'Mac (Apple Silicon)', url: 'https://files.stirlingpdf.com/mac-installer.dmg', value: 'mac-apple' }, + { label: 'Mac (Intel)', url: 'https://files.stirlingpdf.com/mac-x86_64-installer.dmg', value: 'mac-intel' }, + { label: 'Linux', url: 'https://docs.stirlingpdf.com/Installation/Unix%20Installation/', value: 'linux' }, + ]; + return options.filter(opt => opt.url); + }, []); + const { ids: flowSlideIds, type: flowType } = resolveFlow( effectiveEnableLogin, effectiveIsAdmin, @@ -182,9 +193,22 @@ export function useInitialOnboardingState({ onLicenseNoticeUpdate?.(licenseNotice); }, [licenseNotice, onLicenseNoticeUpdate]); + // Initialize ref with default URL + useEffect(() => { + if (!selectedDownloadUrlRef.current && os.url) { + selectedDownloadUrlRef.current = os.url; + } + }, [os.url]); + + const handleDownloadUrlChange = useCallback((url: string) => { + selectedDownloadUrlRef.current = url; + }, []); + const currentSlide = slideDefinition.createSlide({ osLabel: os.label, osUrl: os.url, + osOptions, + onDownloadUrlChange: handleDownloadUrlChange, selectedRole: state.selectedRole, onRoleSelect: handleRoleSelect, licenseNotice, @@ -243,7 +267,7 @@ export function useInitialOnboardingState({ closeAndMarkSeen(); return; case 'download-selected': { - const downloadUrl = os.url || currentSlide.downloadUrl; + const downloadUrl = selectedDownloadUrlRef.current || os.url || currentSlide.downloadUrl; if (downloadUrl) { window.open(downloadUrl, '_blank', 'noopener'); } diff --git a/frontend/src/core/components/onboarding/InitialOnboardingModal/useLicenseInfo.ts b/frontend/src/core/components/onboarding/InitialOnboardingModal/useLicenseInfo.ts deleted file mode 100644 index 2ca04b9c30..0000000000 --- a/frontend/src/core/components/onboarding/InitialOnboardingModal/useLicenseInfo.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { useEffect, useState } from 'react'; -import apiClient from '@app/services/apiClient'; - -interface UseLicenseInfoOptions { - opened: boolean; - shouldFetch: boolean; -} - -export function useLicenseInfo({ opened, shouldFetch }: UseLicenseInfoOptions) { - const [licenseUserCount, setLicenseUserCount] = useState(null); - - useEffect(() => { - if (!opened) { - return; - } - - if (!shouldFetch) { - setLicenseUserCount(null); - return; - } - - let cancelled = false; - - const fetchLicenseInfo = async () => { - try { - const response = await apiClient.get<{ totalUsers?: number }>( - '/api/v1/proprietary/ui-data/admin-settings', - { - suppressErrorToast: true, - } as any, - ); - - if (!cancelled) { - const totalUsers = response.data?.totalUsers; - setLicenseUserCount(typeof totalUsers === 'number' ? totalUsers : null); - } - } catch (error) { - console.error('[onboarding] failed to fetch license information', error); - if (!cancelled) { - setLicenseUserCount(null); - } - } - }; - - fetchLicenseInfo(); - - return () => { - cancelled = true; - }; - }, [opened, shouldFetch]); - - return licenseUserCount; -} - diff --git a/frontend/src/core/components/onboarding/ServerLicenseModal.tsx b/frontend/src/core/components/onboarding/ServerLicenseModal.tsx index bfe906c335..43f6d48976 100644 --- a/frontend/src/core/components/onboarding/ServerLicenseModal.tsx +++ b/frontend/src/core/components/onboarding/ServerLicenseModal.tsx @@ -3,7 +3,7 @@ import { Modal, Button, Group, Stack } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import AnimatedSlideBackground from '@app/components/onboarding/slides/AnimatedSlideBackground'; import ServerLicenseSlide from '@app/components/onboarding/slides/ServerLicenseSlide'; -import { LicenseNotice } from '@app/components/onboarding/slides/types'; +import { LicenseNotice } from '@app/types/types'; import { Z_INDEX_OVER_FULLSCREEN_SURFACE } from '@app/styles/zIndex'; import styles from '@app/components/onboarding/InitialOnboardingModal/InitialOnboardingModal.module.css'; diff --git a/frontend/src/core/components/onboarding/hooks/useOnboardingFlow.ts b/frontend/src/core/components/onboarding/hooks/useOnboardingFlow.ts index 22941b438e..d8b335897b 100644 --- a/frontend/src/core/components/onboarding/hooks/useOnboardingFlow.ts +++ b/frontend/src/core/components/onboarding/hooks/useOnboardingFlow.ts @@ -4,7 +4,7 @@ import { useAppConfig } from '@app/contexts/AppConfigContext'; import { useCookieConsentContext } from '@app/contexts/CookieConsentContext'; import { useOnboarding } from '@app/contexts/OnboardingContext'; import { useAuth } from '@app/auth/UseSession'; -import type { LicenseNotice } from '@app/components/onboarding/slides/types'; +import type { LicenseNotice } from '@app/types/types'; import { useNavigate } from 'react-router-dom'; import { ONBOARDING_SESSION_BLOCK_KEY, diff --git a/frontend/src/core/components/onboarding/onboardingFlowConfig.ts b/frontend/src/core/components/onboarding/onboardingFlowConfig.ts index 780f037725..a7617a1755 100644 --- a/frontend/src/core/components/onboarding/onboardingFlowConfig.ts +++ b/frontend/src/core/components/onboarding/onboardingFlowConfig.ts @@ -3,7 +3,7 @@ import DesktopInstallSlide from '@app/components/onboarding/slides/DesktopInstal import SecurityCheckSlide from '@app/components/onboarding/slides/SecurityCheckSlide'; import PlanOverviewSlide from '@app/components/onboarding/slides/PlanOverviewSlide'; import ServerLicenseSlide from '@app/components/onboarding/slides/ServerLicenseSlide'; -import { SlideConfig, LicenseNotice } from '@app/components/onboarding/slides/types'; +import { SlideConfig, LicenseNotice } from '@app/types/types'; export type SlideId = | 'welcome' @@ -31,9 +31,17 @@ export interface FlowState { selectedRole: 'admin' | 'user' | null; } +export interface OSOption { + label: string; + url: string; + value: string; +} + export interface SlideFactoryParams { osLabel: string; osUrl: string; + osOptions?: OSOption[]; + onDownloadUrlChange?: (url: string) => void; selectedRole: 'admin' | 'user' | null; onRoleSelect: (role: 'admin' | 'user' | null) => void; licenseNotice?: LicenseNotice; @@ -79,7 +87,7 @@ export const SLIDE_DEFINITIONS: Record = { }, 'desktop-install': { id: 'desktop-install', - createSlide: ({ osLabel, osUrl }) => DesktopInstallSlide({ osLabel, osUrl }), + createSlide: ({ osLabel, osUrl, osOptions, onDownloadUrlChange }) => DesktopInstallSlide({ osLabel, osUrl, osOptions, onDownloadUrlChange }), hero: { type: 'dual-icon' }, buttons: [ { diff --git a/frontend/src/core/components/onboarding/slides/AnimatedSlideBackground.tsx b/frontend/src/core/components/onboarding/slides/AnimatedSlideBackground.tsx index d2187e3d56..9367fc7a8b 100644 --- a/frontend/src/core/components/onboarding/slides/AnimatedSlideBackground.tsx +++ b/frontend/src/core/components/onboarding/slides/AnimatedSlideBackground.tsx @@ -1,6 +1,6 @@ import React from 'react'; import styles from './AnimatedSlideBackground.module.css'; -import { AnimatedSlideBackgroundProps } from './types'; +import { AnimatedSlideBackgroundProps } from '../../../types/types'; type CircleStyles = React.CSSProperties & { '--circle-move-x'?: string; diff --git a/frontend/src/core/components/onboarding/slides/DesktopInstallSlide.tsx b/frontend/src/core/components/onboarding/slides/DesktopInstallSlide.tsx index a759611ae5..4cb587385d 100644 --- a/frontend/src/core/components/onboarding/slides/DesktopInstallSlide.tsx +++ b/frontend/src/core/components/onboarding/slides/DesktopInstallSlide.tsx @@ -1,21 +1,34 @@ import React from 'react'; -import { SlideConfig } from './types'; +import { useTranslation } from 'react-i18next'; +import { SlideConfig } from '../../../types/types'; import { UNIFIED_CIRCLE_CONFIG } from './unifiedBackgroundConfig'; +import { DesktopInstallTitle, type OSOption } from './DesktopInstallTitle'; + +export type { OSOption }; interface DesktopInstallSlideProps { osLabel: string; osUrl: string; + osOptions?: OSOption[]; + onDownloadUrlChange?: (url: string) => void; } -export default function DesktopInstallSlide({ osLabel, osUrl }: DesktopInstallSlideProps): SlideConfig { - const title = osLabel ? `Download for ${osLabel}` : 'Download'; +export default function DesktopInstallSlide({ osLabel, osUrl, osOptions = [], onDownloadUrlChange }: DesktopInstallSlideProps): SlideConfig { + const { t } = useTranslation(); return { key: 'desktop-install', - title, + title: ( + + ), body: ( - Stirling works best as a desktop app. You can use it offline, access documents faster, and make edits locally on your computer. + {t('onboarding.desktopInstall.body', 'Stirling works best as a desktop app. You can use it offline, access documents faster, and make edits locally on your computer.')} ), downloadUrl: osUrl, diff --git a/frontend/src/core/components/onboarding/slides/DesktopInstallTitle.tsx b/frontend/src/core/components/onboarding/slides/DesktopInstallTitle.tsx new file mode 100644 index 0000000000..ac42b518b3 --- /dev/null +++ b/frontend/src/core/components/onboarding/slides/DesktopInstallTitle.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Menu, ActionIcon } from '@mantine/core'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; + +export interface OSOption { + label: string; + url: string; + value: string; +} + +interface DesktopInstallTitleProps { + osLabel: string; + osUrl: string; + osOptions: OSOption[]; + onDownloadUrlChange?: (url: string) => void; +} + +export const DesktopInstallTitle: React.FC = ({ + osLabel, + osUrl, + osOptions, + onDownloadUrlChange +}) => { + const { t } = useTranslation(); + const [selectedOsUrl, setSelectedOsUrl] = React.useState(osUrl); + + React.useEffect(() => { + setSelectedOsUrl(osUrl); + }, [osUrl]); + + const handleOsSelect = React.useCallback((option: OSOption) => { + setSelectedOsUrl(option.url); + onDownloadUrlChange?.(option.url); + }, [onDownloadUrlChange]); + + const currentOsOption = osOptions.find(opt => opt.url === selectedOsUrl) || + (osOptions.length > 0 ? osOptions[0] : { label: osLabel, url: osUrl }); + + const displayLabel = currentOsOption.label || osLabel; + const title = displayLabel + ? t('onboarding.desktopInstall.titleWithOs', 'Download for {{osLabel}}', { osLabel: displayLabel }) + : t('onboarding.desktopInstall.title', 'Download'); + + // If only one option or no options, don't show dropdown + if (osOptions.length <= 1) { + return
{title}
; + } + + return ( +
+ {title} + + + + + + + + {osOptions.map((option) => { + const isSelected = option.url === selectedOsUrl; + return ( + handleOsSelect(option)} + style={{ + backgroundColor: isSelected + ? 'light-dark(var(--mantine-color-blue-1), var(--mantine-color-blue-8))' + : 'transparent', + color: isSelected + ? 'light-dark(var(--mantine-color-blue-9), var(--mantine-color-white))' + : 'inherit', + }} + > + {option.label} + + ); + })} + + +
+ ); +}; + diff --git a/frontend/src/core/components/onboarding/slides/PlanOverviewSlide.tsx b/frontend/src/core/components/onboarding/slides/PlanOverviewSlide.tsx index d344f68f76..39287c8b51 100644 --- a/frontend/src/core/components/onboarding/slides/PlanOverviewSlide.tsx +++ b/frontend/src/core/components/onboarding/slides/PlanOverviewSlide.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { SlideConfig, LicenseNotice } from './types'; +import { useTranslation, Trans } from 'react-i18next'; +import { SlideConfig, LicenseNotice } from '../../../types/types'; import { UNIFIED_CIRCLE_CONFIG } from './unifiedBackgroundConfig'; interface PlanOverviewSlideProps { @@ -10,21 +11,28 @@ interface PlanOverviewSlideProps { const DEFAULT_FREE_TIER_LIMIT = 5; export default function PlanOverviewSlide({ isAdmin, licenseNotice }: PlanOverviewSlideProps): SlideConfig { + const { t } = useTranslation(); const freeTierLimit = licenseNotice?.freeTierLimit ?? DEFAULT_FREE_TIER_LIMIT; const adminBody = ( - As an admin, you can manage users, configure settings, and monitor server health. The first{' '} - {freeTierLimit} people on your server get to use Stirling free of charge. + }} + values={{ freeTierLimit }} + defaults="As an admin, you can manage users, configure settings, and monitor server health. The first {{freeTierLimit}} people on your server get to use Stirling free of charge." + /> ); return { key: isAdmin ? 'admin-overview' : 'plan-overview', - title: isAdmin ? 'Admin Overview' : 'Plan Overview', + title: isAdmin + ? t('onboarding.planOverview.adminTitle', 'Admin Overview') + : t('onboarding.planOverview.userTitle', 'Plan Overview'), body: isAdmin ? adminBody : ( - Invite teammates, assign roles, and keep your documents organized in one secure workspace. Enable login mode whenever you're ready to grow beyond solo use. + {t('onboarding.planOverview.userBody', 'Invite teammates, assign roles, and keep your documents organized in one secure workspace. Enable login mode whenever you\'re ready to grow beyond solo use.')} ), background: { diff --git a/frontend/src/core/components/onboarding/slides/SecurityCheckSlide.tsx b/frontend/src/core/components/onboarding/slides/SecurityCheckSlide.tsx index 33f95298b4..6cfc136ed1 100644 --- a/frontend/src/core/components/onboarding/slides/SecurityCheckSlide.tsx +++ b/frontend/src/core/components/onboarding/slides/SecurityCheckSlide.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Select } from '@mantine/core'; import styles from '../InitialOnboardingModal/InitialOnboardingModal.module.css'; -import { SlideConfig } from './types'; +import { SlideConfig } from '../../../types/types'; import LocalIcon from '@app/components/shared/LocalIcon'; import { UNIFIED_CIRCLE_CONFIG } from './unifiedBackgroundConfig'; import i18n from '@app/i18n'; diff --git a/frontend/src/core/components/onboarding/slides/ServerLicenseSlide.tsx b/frontend/src/core/components/onboarding/slides/ServerLicenseSlide.tsx index 3c2156c75e..4b2f9873b8 100644 --- a/frontend/src/core/components/onboarding/slides/ServerLicenseSlide.tsx +++ b/frontend/src/core/components/onboarding/slides/ServerLicenseSlide.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Trans } from 'react-i18next'; -import { SlideConfig, LicenseNotice } from './types'; +import { SlideConfig, LicenseNotice } from '../../../types/types'; import { UNIFIED_CIRCLE_CONFIG } from './unifiedBackgroundConfig'; import i18n from '@app/i18n'; diff --git a/frontend/src/core/components/onboarding/slides/WelcomeSlide.tsx b/frontend/src/core/components/onboarding/slides/WelcomeSlide.tsx index 5732413d88..4c5dca2d28 100644 --- a/frontend/src/core/components/onboarding/slides/WelcomeSlide.tsx +++ b/frontend/src/core/components/onboarding/slides/WelcomeSlide.tsx @@ -1,16 +1,17 @@ import React from 'react'; -import { Trans } from 'react-i18next'; -import { SlideConfig } from './types'; +import { useTranslation, Trans } from 'react-i18next'; +import { SlideConfig } from '../../../types/types'; import styles from '../InitialOnboardingModal/InitialOnboardingModal.module.css'; import { UNIFIED_CIRCLE_CONFIG } from './unifiedBackgroundConfig'; -import i18n from '@app/i18n'; export default function WelcomeSlide(): SlideConfig { + const { t } = useTranslation(); + return { key: 'welcome', title: ( - {i18n.t('onboarding.welcomeSlide.title', 'Welcome to Stirling')} + {t('onboarding.welcomeSlide.title', 'Welcome to Stirling')} V2 @@ -20,11 +21,8 @@ export default function WelcomeSlide(): SlideConfig { , - br:
, - }} - defaults="Stirling PDF is now ready for teams of all sizes.
This update includes a new layout, powerful new admin capabilities, and our most requested feature - Edit Text." + components={{ strong: }} + defaults="Stirling PDF is now ready for teams of all sizes. This update includes a new layout, powerful new admin capabilities, and our most requested feature - Edit Text." />
), diff --git a/frontend/src/core/components/onboarding/slides/unifiedBackgroundConfig.ts b/frontend/src/core/components/onboarding/slides/unifiedBackgroundConfig.ts index 393b341568..f7b2fa111e 100644 --- a/frontend/src/core/components/onboarding/slides/unifiedBackgroundConfig.ts +++ b/frontend/src/core/components/onboarding/slides/unifiedBackgroundConfig.ts @@ -1,4 +1,4 @@ -import { AnimatedCircleConfig } from './types'; +import { AnimatedCircleConfig } from '../../../types/types'; /** * Unified circle background configuration used across all onboarding slides. diff --git a/frontend/src/core/components/shared/QuickAccessBar.tsx b/frontend/src/core/components/shared/QuickAccessBar.tsx index 29a1cfeabc..3c3c69d5a4 100644 --- a/frontend/src/core/components/shared/QuickAccessBar.tsx +++ b/frontend/src/core/components/shared/QuickAccessBar.tsx @@ -270,12 +270,7 @@ const QuickAccessBar = forwardRef((_, ref) => {
- startTour('tools', { - source: 'quick-access-help-button', - metadata: { entry: 'direct' }, - }) - } + onClick={() => startTour('tools')} > {renderNavButton(buttonConfig, index)}
@@ -292,12 +287,7 @@ const QuickAccessBar = forwardRef((_, ref) => { } - onClick={() => - startTour('tools', { - source: 'quick-access-help-menu', - metadata: { entry: 'menu-tools' }, - }) - } + onClick={() => startTour('tools')} >
@@ -310,12 +300,7 @@ const QuickAccessBar = forwardRef((_, ref) => { } - onClick={() => - startTour('admin', { - source: 'quick-access-help-menu', - metadata: { entry: 'menu-admin' }, - }) - } + onClick={() => startTour('admin')} >
diff --git a/frontend/src/core/constants/events.ts b/frontend/src/core/constants/events.ts index 1c84f456fb..c8adc99381 100644 --- a/frontend/src/core/constants/events.ts +++ b/frontend/src/core/constants/events.ts @@ -1,4 +1,4 @@ -import type { LicenseNotice } from '@app/components/onboarding/slides/types'; +import type { LicenseNotice } from '@app/types/types'; export const ONBOARDING_SESSION_BLOCK_KEY = 'stirling-onboarding-session-active'; export const ONBOARDING_SESSION_EVENT = 'stirling:onboarding-session-started'; diff --git a/frontend/src/core/components/onboarding/slides/types.ts b/frontend/src/core/types/types.ts similarity index 100% rename from frontend/src/core/components/onboarding/slides/types.ts rename to frontend/src/core/types/types.ts