From 981ce1d1b2c2ced48fb94d631dcf565d01258f9d Mon Sep 17 00:00:00 2001 From: Arek Bykowski Date: Sun, 15 Feb 2026 18:43:34 +0100 Subject: [PATCH] =?UTF-8?q?Sprz=C4=85tanie=20projektu=20-=20dodanie=20podg?= =?UTF-8?q?l=C4=85du=20gpx=20-=20dodanie=20obs=C5=82ugi=20logo=20i=20avata?= =?UTF-8?q?ra=20-=20dodanie=20editable=20config=20do=20prostej=20edycji=20?= =?UTF-8?q?tekst=C3=B3w=20na=20stronie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 8196 bytes App.tsx | 198 +++++++----------- .../ai_prompts.ts | 90 ++++++-- _EDITABLE_CONFIG/author.ts | 10 + _EDITABLE_CONFIG/ui_text.ts | 143 +++++++++++++ components/StepContext.tsx | 37 ++-- components/StepDetails.tsx | 169 +++++++-------- components/StepEventType.tsx | 20 +- components/StepPlatform.tsx | 20 +- components/StepResult.tsx | 57 ++--- components/StepToneGoal.tsx | 27 +-- prompts/index.ts | 72 ------- services/geminiService.ts | 2 +- 13 files changed, 459 insertions(+), 386 deletions(-) rename prompts/modular.ts => _EDITABLE_CONFIG/ai_prompts.ts (81%) create mode 100644 _EDITABLE_CONFIG/author.ts create mode 100644 _EDITABLE_CONFIG/ui_text.ts delete mode 100644 prompts/index.ts diff --git a/.DS_Store b/.DS_Store index b9b53951f20f983c7fc104acc4e7c5f7fb4f4f2c..2e5e93b548b608f315d1d12a0f7d6512c94fab64 100644 GIT binary patch literal 8196 zcmeHM&u=3&6n^e@>15k(r`r_DBBW?@LE5SmS`Y}K&896&1WT)?D((ItOfr*n=){g@ zCTY7>r5rfH3GUpuaOH%=g(DZP+z@{P9JuTWKHHPcBxyM!v};%Pdt<-P_WNv)^QJ_^ zif#8bq6H$dkfpRIQJj-xyUZhLEUB4;WWW>c&}}NxhqOVJ5o=Rn7%&VN1`Gp+0mH!m zfdSmvGFcbg`?}SXh5^ICGs%E_Kje_5EF`k4rFwOsP$2;1II2~GjyOPJa)~S?va6+n zqE8(?umsAI5QAwr+H=wzvXIEGmKsh>!-*v$vm`=cYINXo%A8n1OH&#K3R2qoi*JzVIqW4gHrxb`ikFvvWn-7dFF!Y7O<0rG!}5VRD#uRTj*3orUq0;!5mbA+Q{DBwql%qf6Fhc& z?u82AyB^XPZm?)j9tGC4JUb;h2( zHaDA{ou8k7{)L4XufKG?V$W5b+F>J1SK5y*B-f>*^A9)q~ z+K}nC=YG#Cfl!2-Q5X2kE{MR>-ETs_fq zS>knp5j$Xcvn89NT`!CvM=*Q)P8d48;T2CF22RxrHhEFRv1so3HNo}FXH>U%+zLI} zW&YNmn#g?NgP!t=R&2^^1@Tk1rzMi*f2wztzQYCgGWo)mZpq+B&P^P|yR?f#{D{7y zZ|FPvk$$G%=ns0#CYa4`u$yd^y~}Q~_gRVEV>Ncbd=}~s#(K;AvVQKBEP|F==1w`} zf#40)O2k!lkYn}Akgw7HAssz%^5yYY>VWo!F!HHm;F9)eLB{_Z7k~eM>ijki83qgk zeFoV0dU+l1eRWs#tNYp*)Ex4s$TG=0rK_d7kWfeyS+Bxz$S40Wgq};<3W@A$i58^) R{6m1b|IPiccHXmH`~$;A;;R4v delta 331 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{Mvv5r;6q~50C<@{*g2hT0iWw?AbMljuayAw& zXJ!?5GaY7dk*pIjthz{ap1%v>R$&ngdQ-4W1ZW9$br1q5}$Dwj`o64ZjITt2x- z&=jn4`Q$Z%MkZjD%m0G`P!9tGJ3|3O5ko#hE|3P=4Y4^t2`B?{6VP5p@ySmFb-<

Hz5Ba0E p9D>XsCjhPD1`@8I@Yq=Roq009j3>x)1|~>IfdY?Vb3D%+W&ox0Mlb*X diff --git a/App.tsx b/App.tsx index 69130e8..9e76762 100644 --- a/App.tsx +++ b/App.tsx @@ -11,11 +11,13 @@ import { ChevronLeft, ExternalLink, Sparkles, User, Lock, ArrowRight, AlertCircl import { generateStoryContent } from './services/geminiService'; import { getEnvVar } from './utils/envUtils'; +// --- CONFIG IMPORT --- +import { AUTHOR_CONFIG } from './_EDITABLE_CONFIG/author'; +import { UI_TEXT } from './_EDITABLE_CONFIG/ui_text'; + const STORAGE_KEY = 'gpx-storyteller-state-v6'; const AUTH_KEY = 'promptstory-auth-token'; -// --- PASSWORD CONFIGURATION --- -// STRICT MODE: No fallbacks. The environment variable must be set in Coolify/Vercel/Netlify. const APP_PASSWORD = getEnvVar('VITE_APP_PASSWORD'); const INITIAL_STATE: WizardState = { @@ -44,12 +46,9 @@ const INITIAL_STATE: WizardState = { } }; -// --- LOGIN SCREEN COMPONENT --- const LoginScreen: React.FC<{ onLogin: (success: boolean) => void }> = ({ onLogin }) => { const [input, setInput] = useState(''); const [error, setError] = useState(false); - - // Check if password is misconfigured (empty) const isConfigMissing = !APP_PASSWORD; const handleSubmit = (e: React.FormEvent) => { @@ -67,16 +66,10 @@ const LoginScreen: React.FC<{ onLogin: (success: boolean) => void }> = ({ onLogi

-

Błąd Konfiguracji

+

{UI_TEXT.login.configError}

- Aplikacja nie wykryła hasła w zmiennych środowiskowych. + Missing VITE_APP_PASSWORD.

-
-

Brakuje zmiennej: VITE_APP_PASSWORD

-

Jeśli używasz Coolify/Vercel:

-

1. Dodaj zmienną w panelu.

-

2. Przebuduj projekt (Re-deploy).

-
); @@ -85,83 +78,66 @@ const LoginScreen: React.FC<{ onLogin: (success: boolean) => void }> = ({ onLogi return (
-
-
-

Dostęp Chroniony

-

Wprowadź hasło, aby uzyskać dostęp.

+

{UI_TEXT.login.title}

+

{UI_TEXT.login.desc}

-
-
- { - setInput(e.target.value); - setError(false); - }} - placeholder="Hasło..." - className={`w-full p-4 border rounded-lg outline-none transition-all font-medium text-center tracking-widest ${ - error - ? 'border-red-300 bg-red-50 focus:border-red-500' - : 'border-gray-200 focus:border-[#EA4420] focus:ring-1 focus:ring-[#EA4420]' - }`} - autoFocus - /> -
- + { + setInput(e.target.value); + setError(false); + }} + placeholder="Hasło..." + className={`w-full p-4 border rounded-lg outline-none transition-all font-medium text-center tracking-widest ${ + error + ? 'border-red-300 bg-red-50 focus:border-red-500' + : 'border-gray-200 focus:border-[#EA4420] focus:ring-1 focus:ring-[#EA4420]' + }`} + autoFocus + /> {error && (
- Nieprawidłowe hasło + {UI_TEXT.login.error}
)} -
- -

- PromptStory v1.2 • Secure Production Build -

); }; const App: React.FC = () => { - // Auth State const [isAuthenticated, setIsAuthenticated] = useState(false); const [isAuthChecking, setIsAuthChecking] = useState(true); - - // App State const [data, setData] = useState(INITIAL_STATE); const [generatedContent, setGeneratedContent] = useState(null); const [isGenerating, setIsGenerating] = useState(false); const [isLoaded, setIsLoaded] = useState(false); const [errorMessage, setErrorMessage] = useState(null); - // Image loading states - const [logoError, setLogoError] = useState(false); - const [avatarError, setAvatarError] = useState(false); + // LOGO & AVATAR STATE + const [logoLoaded, setLogoLoaded] = useState(false); + const [avatarLoaded, setAvatarLoaded] = useState(false); - // 1. Check Auth on Mount useEffect(() => { const storedAuth = localStorage.getItem(AUTH_KEY); - if (storedAuth === 'true') { - setIsAuthenticated(true); - } + if (storedAuth === 'true') setIsAuthenticated(true); setIsAuthChecking(false); }, []); @@ -178,21 +154,18 @@ const App: React.FC = () => { resetApp(); }; - // 2. Load Data Persistence Logic useEffect(() => { const saved = localStorage.getItem(STORAGE_KEY); if (saved) { try { const parsed = JSON.parse(saved); - parsed.files = []; // Reset files - + parsed.files = []; if (!parsed.stats) parsed.stats = { distance: '', duration: '', elevation: '' }; if (!parsed.waypoints) parsed.waypoints = []; if (!parsed.tripData) parsed.tripData = { ...INITIAL_STATE.tripData }; if (!parsed.tone) parsed.tone = null; if (!parsed.goal) parsed.goal = null; if (!parsed.storyStyle) parsed.storyStyle = null; - setData(parsed); } catch (e) { console.error("Failed to load state", e); @@ -216,37 +189,28 @@ const App: React.FC = () => { }; const nextStep = () => { - if (data.step < Step.RESULT) { - updateData({ step: data.step + 1 }); - } + if (data.step < Step.RESULT) updateData({ step: data.step + 1 }); }; const prevStep = () => { - if (data.step > Step.CONTEXT) { - updateData({ step: data.step - 1 }); - } + if (data.step > Step.CONTEXT) updateData({ step: data.step - 1 }); }; const handleGenerate = async () => { setIsGenerating(true); setErrorMessage(null); - - // STRICT MODE: Use VITE_API_KEY const apiKey = getEnvVar('VITE_API_KEY'); - if (!apiKey) { - setErrorMessage("BŁĄD KRYTYCZNY: Brak klucza API (VITE_API_KEY). Skonfiguruj zmienne w panelu Coolify."); + setErrorMessage("BŁĄD: Brak VITE_API_KEY."); setIsGenerating(false); return; } - try { const content = await generateStoryContent(data, apiKey); setGeneratedContent(content); updateData({ step: Step.RESULT }); } catch (error: any) { - console.error("Generowanie nie powiodło się:", error); - setErrorMessage("Błąd generowania: " + (error.message || 'Sprawdź konsolę')); + setErrorMessage("Błąd: " + (error.message || 'Unknown')); } finally { setIsGenerating(false); } @@ -255,15 +219,12 @@ const App: React.FC = () => { const handleRegenerate = async (slideCount: number, feedback: string) => { setIsGenerating(true); setErrorMessage(null); - const apiKey = getEnvVar('VITE_API_KEY'); - try { const content = await generateStoryContent(data, apiKey || '', { slideCount, feedback }); setGeneratedContent(content); } catch (error: any) { - console.error("Regenerowanie nie powiodło się:", error); - setErrorMessage("Błąd regenerowania: " + (error.message || '')); + setErrorMessage("Błąd: " + (error.message || '')); } finally { setIsGenerating(false); } @@ -277,39 +238,34 @@ const App: React.FC = () => { }; if (isAuthChecking || !isLoaded) return null; - - if (!isAuthenticated) { - return ; - } - - const stepsLabels = ['Kontekst', 'Typ', 'Platforma', 'Vibe & Cel', 'Szczegóły']; + if (!isAuthenticated) return ; return (
- {!logoError ? ( - setLogoError(true)} - alt="PromptStory Logo" - className="w-10 h-10 object-contain" - /> - ) : ( -
- + alt="Logo" + onLoad={() => setLogoLoaded(true)} + className={`h-10 object-contain ${logoLoaded ? 'block' : 'hidden'}`} + /> + {!logoLoaded && ( +
+
+

{UI_TEXT.header.appTitle}

)} -

PromptStory

@@ -319,17 +275,14 @@ const App: React.FC = () => { {data.step !== Step.RESULT && (
- {stepsLabels.map((label, idx) => ( + {UI_TEXT.steps.labels.map((label, idx) => ( = idx ? 'text-[#EA4420]' : 'text-gray-300'}`}> 0{idx + 1}. {label} ))}
-
+
)} @@ -339,22 +292,8 @@ const App: React.FC = () => { {data.step === Step.EVENT_TYPE && } {data.step === Step.PLATFORM && } {data.step === Step.TONE_GOAL && } - {data.step === Step.DETAILS && ( - - )} - {data.step === Step.RESULT && generatedContent && ( - - )} + {data.step === Step.DETAILS && } + {data.step === Step.RESULT && generatedContent && } {errorMessage && (
@@ -372,26 +311,28 @@ const App: React.FC = () => { className="flex items-center space-x-2 text-gray-500 hover:text-gray-900 font-semibold px-6 py-3 rounded-md border border-gray-200 hover:bg-gray-50 transition-colors disabled:opacity-50" > - Wróć + {UI_TEXT.steps.nav.back}
)} + {/* FOOTER - Uses AUTHOR_CONFIG */}