feat(branding,auth): Update app description and improve authentication flow
- Update manifest.json and layout metadata with comprehensive Synapsis description emphasizing decentralized infrastructure and global signal layer concept - Expand login page default node description to match updated branding messaging - Replace Next.js router navigation with hard window.location.href redirect to ensure authentication cookies are properly picked up after login/import - Remove unused router and ShieldAlert imports from login page - Add accent color luminance detection to ToastContext for dynamic text color contrast - Implement intelligent text color selection in success toasts based on accent color brightness to ensure readability - These changes improve authentication reliability and ensure consistent branding messaging across the application
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Synapsis",
|
"name": "Synapsis",
|
||||||
"short_name": "Synapsis",
|
"short_name": "Synapsis",
|
||||||
"description": "Federated social network infrastructure",
|
"description": "Synapsis is designed to function like a global signal layer rather than a culture-bound platform. Anyone can run their own node and still participate in a shared, interconnected network.",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "#0a0a0a",
|
"background_color": "#0a0a0a",
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ const sairaCondensed = Saira_Condensed({
|
|||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Synapsis",
|
title: "Synapsis",
|
||||||
description: "Federated social network infrastructure",
|
description: "Synapsis is designed to function like a global signal layer rather than a culture-bound platform. Anyone can run their own node and still participate in a shared, interconnected network, with global identity, clean terminology, and a modern interface that feels current rather than experimental.",
|
||||||
manifest: "/manifest.json",
|
manifest: "/manifest.json",
|
||||||
icons: {
|
icons: {
|
||||||
icon: "/favicon.png",
|
icon: "/favicon.png",
|
||||||
|
|||||||
+6
-10
@@ -2,12 +2,10 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/navigation';
|
|
||||||
import { SynapsisLogo } from '@/components/Icons';
|
import { SynapsisLogo } from '@/components/Icons';
|
||||||
import { TriangleAlert, ShieldAlert } from 'lucide-react';
|
import { TriangleAlert } from 'lucide-react';
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const router = useRouter();
|
|
||||||
const [mode, setMode] = useState<'login' | 'register' | 'import'>('login');
|
const [mode, setMode] = useState<'login' | 'register' | 'import'>('login');
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
@@ -33,7 +31,7 @@ export default function LoginPage() {
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
setNodeInfo({
|
setNodeInfo({
|
||||||
name: data.name || '',
|
name: data.name || '',
|
||||||
description: data.description || 'Federated social network infrastructure'
|
description: data.description || 'Synapsis is designed to function like a global signal layer rather than a culture-bound platform. Anyone can run their own node and still participate in a shared, interconnected network, with global identity, clean terminology, and a modern interface that feels current rather than experimental. Synapsis aims to be neutral, resilient infrastructure for human and machine discourse, more like a protocol or nervous system than a social club.'
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => { });
|
.catch(() => { });
|
||||||
@@ -98,11 +96,9 @@ export default function LoginPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setImportSuccess(data.message);
|
setImportSuccess(data.message);
|
||||||
// After successful import, the user is typically logged in (depends on API implementation)
|
// Hard redirect to ensure cookie is picked up
|
||||||
// But let's redirect to login or home if the API returns success
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
router.push('/');
|
window.location.href = '/';
|
||||||
router.refresh();
|
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -141,8 +137,8 @@ export default function LoginPage() {
|
|||||||
throw new Error(data.error || 'Authentication failed');
|
throw new Error(data.error || 'Authentication failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
router.push('/');
|
// Hard redirect to ensure cookie is picked up
|
||||||
router.refresh();
|
window.location.href = '/';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err instanceof Error ? err.message : 'An error occurred');
|
setError(err instanceof Error ? err.message : 'An error occurred');
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { createContext, useContext, useState, useCallback, ReactNode } from 'react';
|
import { createContext, useContext, useState, useCallback, ReactNode } from 'react';
|
||||||
|
import { useAccentColor } from './AccentColorContext';
|
||||||
|
|
||||||
type ToastType = 'success' | 'error' | 'info';
|
type ToastType = 'success' | 'error' | 'info';
|
||||||
|
|
||||||
@@ -18,6 +19,16 @@ interface ToastContextType {
|
|||||||
|
|
||||||
const ToastContext = createContext<ToastContextType | null>(null);
|
const ToastContext = createContext<ToastContextType | null>(null);
|
||||||
|
|
||||||
|
// Check if a color is light (needs dark text)
|
||||||
|
function isLightColor(hex: string): boolean {
|
||||||
|
const color = hex.replace('#', '');
|
||||||
|
const r = parseInt(color.slice(0, 2), 16);
|
||||||
|
const g = parseInt(color.slice(2, 4), 16);
|
||||||
|
const b = parseInt(color.slice(4, 6), 16);
|
||||||
|
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
||||||
|
return luminance > 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
export function ToastProvider({ children }: { children: ReactNode }) {
|
export function ToastProvider({ children }: { children: ReactNode }) {
|
||||||
const [toasts, setToasts] = useState<Toast[]>([]);
|
const [toasts, setToasts] = useState<Toast[]>([]);
|
||||||
|
|
||||||
@@ -50,6 +61,9 @@ export function useToast() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast: (id: string) => void }) {
|
function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast: (id: string) => void }) {
|
||||||
|
const { accentColor } = useAccentColor();
|
||||||
|
const needsDarkText = isLightColor(accentColor);
|
||||||
|
|
||||||
if (toasts.length === 0) return null;
|
if (toasts.length === 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -77,9 +91,11 @@ function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast:
|
|||||||
: toast.type === 'success'
|
: toast.type === 'success'
|
||||||
? 'var(--accent)'
|
? 'var(--accent)'
|
||||||
: 'var(--background-secondary)',
|
: 'var(--background-secondary)',
|
||||||
color: toast.type === 'error' || toast.type === 'success'
|
color: toast.type === 'error'
|
||||||
? '#fff'
|
? '#fff'
|
||||||
: 'var(--foreground)',
|
: toast.type === 'success'
|
||||||
|
? (needsDarkText ? '#000' : '#fff')
|
||||||
|
: 'var(--foreground)',
|
||||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
|
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
|
|||||||
Reference in New Issue
Block a user