feat(legal): imprint & privacy notices, "Über MindSift"

- LEGAL_IMPRINT_/LEGAL_PRIVACY_ URL and Markdown (inline or *_FILE);
  only http(s) URLs accepted
- /auth/status exposes legal info; public GET /legal/{imprint|privacy}
- Links on login/setup screen and in the settings footer: URL opens a new
  tab, Markdown a reading modal; hidden when nothing is configured
- "Über MindSift" modal (version, license, repository) in settings and help
- Docs and compose/env examples

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-28 23:10:27 +01:00
1 parent a62b204e14
commit d6c70d7a8e
17 files changed
+318 -2

No files matched your search

@@ -20,11 +20,13 @@ import {
Pencil,
Copy,
} from 'lucide-react';
import { APIKey, User, UserTheme } from '../../lib/types';
import { APIKey, AuthStatus, User, UserTheme } from '../../lib/types';
import { api, triggerHaptic } from '../../lib/api';
import { customThemeId, ThemeId, ThemeOption } from '../../lib/theme';
import themeTemplateCss from '../../themes/theme-template.css?raw';
import { UserAvatar, resizeImageToDataUrl } from '../../components/UserAvatar';
import { LegalLinks } from '../../components/LegalLinks';
import { AboutModal } from '../../components/AboutModal';
interface UserSettingsViewProps {
currentUser: User;
@@ -50,6 +52,11 @@ export const UserSettingsView: React.FC<UserSettingsViewProps> = ({
onBack,
}) => {
const [section, setSection] = useState<UserSettingsSection>('profile');
const [legal, setLegal] = useState<AuthStatus['legal']>();
const [showAbout, setShowAbout] = useState(false);
useEffect(() => {
api.getAuthStatus().then((st) => setLegal(st.legal)).catch(() => {});
}, []);
// --- Custom Theme Editor State ---
const [themeEditId, setThemeEditId] = useState<string | null>(null); // null = new theme
@@ -1227,6 +1234,14 @@ export const UserSettingsView: React.FC<UserSettingsViewProps> = ({
)}
</div>
</div>
{/* Footer: legal notices of this instance and project info */}
<LegalLinks legal={legal} className="pt-4 border-t border-border">
<button type="button" onClick={() => setShowAbout(true)} className="hover:text-main underline-offset-2 hover:underline">
Über MindSift
</button>
</LegalLinks>
{showAbout && <AboutModal onClose={() => setShowAbout(false)} />}
</div>
);
};