diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..80eedc0b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository + +buy_me_a_coffee: theluap diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 633af451..871607d3 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -3572,6 +3572,19 @@ "finish": "Einrichtung abschließen", "saveFailed": "Einige Einstellungen konnten nicht gespeichert werden — Sie können sie in den Einstellungen abschließen." }, + "community": { + "subtitle": "Alles bereit", + "mission": "PicPeak gibt es, damit Fotografinnen und Fotografen ihre Galerien und Kundendaten selbst besitzen — auf dem eigenen Server, ohne monatliche SaaS-Gebühren. Danke, dass du es ausprobierst.", + "bugTitle": "Fehler gefunden?", + "bugDesc": "Melde ihn und wir sehen ihn uns an.", + "featureTitle": "Wunschfunktion?", + "featureDesc": "Sag uns, was PicPeak für dich besser machen würde.", + "starTitle": "Gefällt es dir? Erzähl davon", + "starDesc": "Empfiehl es anderen Fotografen, teile es und gib dem Projekt einen Stern auf GitHub.", + "supportTitle": "Entwicklung unterstützen", + "supportDesc": "Optional — spendier mir einen Kaffee, um PicPeak am Leben zu halten.", + "finish": "Fertig → Dashboard" + }, "stepOf": "Schritt {{current}} von {{total}}", "continue": "Weiter", "back": "Zurück", diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index fbb30759..f6f85e94 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -3468,6 +3468,19 @@ "finish": "Finish setup", "saveFailed": "Some settings could not be saved — you can finish them in Settings." }, + "community": { + "subtitle": "You're all set", + "mission": "PicPeak exists so photographers can own their galleries and client data — on their own server, without monthly SaaS fees. Thanks for giving it a try.", + "bugTitle": "Found a bug?", + "bugDesc": "Open an issue and we'll take a look.", + "featureTitle": "Want a feature?", + "featureDesc": "Tell us what would make PicPeak better for you.", + "starTitle": "Like it? Spread the word", + "starDesc": "Tell other photographers, share it, and star the project on GitHub.", + "supportTitle": "Support development", + "supportDesc": "Optional — buy me a coffee to help keep PicPeak going.", + "finish": "Finish → Dashboard" + }, "stepOf": "Step {{current}} of {{total}}", "continue": "Continue", "back": "Back", diff --git a/frontend/src/pages/SetupPage.tsx b/frontend/src/pages/SetupPage.tsx index 790c01e7..12af1f46 100644 --- a/frontend/src/pages/SetupPage.tsx +++ b/frontend/src/pages/SetupPage.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { Navigate, useNavigate } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; -import { Key, Mail, Lock, Eye, EyeOff, AlertCircle, ArrowLeft, ArrowRight, Copy, Check, ExternalLink } from 'lucide-react'; +import { Key, Mail, Lock, Eye, EyeOff, AlertCircle, ArrowLeft, ArrowRight, Copy, Check, ExternalLink, Bug, Lightbulb, Star, Coffee } from 'lucide-react'; import { toast } from 'react-toastify'; import { useTranslation } from 'react-i18next'; @@ -19,6 +19,20 @@ import type { AdminUser } from '../types'; const SETUP_DOCS_URL = 'https://github.com/PicPeak/picpeak/blob/main/README.md#first-run--create-your-admin-account'; +// Final "own your data" thank-you step (#732). Link cards shown once, on +// first-run only, before entering the app. Every link is optional and opens +// in a new tab; nothing here makes an external call. +const COMMUNITY_LINKS: { + key: string; + href: string; + icon: React.ComponentType<{ className?: string }>; +}[] = [ + { key: 'bug', href: 'https://github.com/PicPeak/picpeak/issues/new?template=bug_report.md', icon: Bug }, + { key: 'feature', href: 'https://github.com/PicPeak/picpeak/issues/new?template=feature_request.md', icon: Lightbulb }, + { key: 'star', href: 'https://github.com/PicPeak/picpeak', icon: Star }, + { key: 'support', href: 'https://www.buymeacoffee.com/theluap', icon: Coffee }, +]; + // "How will you use PicPeak?" — the opt-in feature groups shown after the admin // account is created. galleries/analytics/userManagement are always on and not // listed. Labels/descriptions reuse the existing Settings→Features i18n keys @@ -53,7 +67,7 @@ export const SetupPage: React.FC = () => { staleTime: Infinity, }); - const [step, setStep] = useState<'token' | 'account' | 'usage' | 'restore' | 'config'>('token'); + const [step, setStep] = useState<'token' | 'account' | 'usage' | 'restore' | 'config' | 'community'>('token'); const [form, setForm] = useState({ token: '', email: '', password: '', confirm: '' }); const [showPassword, setShowPassword] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); @@ -234,8 +248,9 @@ export const SetupPage: React.FC = () => { selectedFeatures.has('reminderEmails') || selectedFeatures.has('incomingMail') || selectedFeatures.has('whatsapp'); - if (needsConfig) setStep('config'); - else navigate('/admin/dashboard', { replace: true }); + // Both the config branch and the no-config path end on the final + // community/thank-you step (#732), whose Finish button enters the app. + setStep(needsConfig ? 'config' : 'community'); } }; @@ -267,7 +282,9 @@ export const SetupPage: React.FC = () => { ? t('setup.restoreStepSubtitle') : step === 'config' ? t('setup.config.subtitle') - : t('setup.usageSubtitle')} + : step === 'community' + ? t('setup.community.subtitle') + : t('setup.usageSubtitle')}

{(step === 'token' || step === 'account' || step === 'usage') && (

@@ -397,7 +414,15 @@ export const SetupPage: React.FC = () => { /> -

+ {/* Stacked full-width (not a side-by-side flex row): the primary + label + loading spinner exceeded the card width when squeezed + next to Back, so the button overflowed the card outline while + submitting (#730). Full-width also keeps longer translations + (e.g. German) inside the button. Matches every other step. */} +
+ -
) : step === 'usage' ? ( @@ -486,11 +509,49 @@ export const SetupPage: React.FC = () => { {t('setup.back')}
- ) : ( + ) : step === 'config' ? ( navigate('/admin/dashboard', { replace: true })} + onDone={() => setStep('community')} /> + ) : ( +
+

{t('setup.community.mission')}

+ +
+ {COMMUNITY_LINKS.map(({ key, href, icon: Icon }) => ( + + + + + {t(`setup.community.${key}Title`)} + + + {t(`setup.community.${key}Desc`)} + + + + ))} +
+ + +
)}