diff --git a/src/App.tsx b/src/App.tsx index 5b342f30..944e1b19 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -20,9 +20,8 @@ import PublicRoute from './components/PublicRoute.tsx' import ProtectedRoute from './components/ProtectedRoute.tsx' import ProfilePage from './pages/ProfilePage.tsx' import Contributors from './pages/Contributors.tsx' -import DashboardPage from './pages/DashboardPage.tsx' -import PrivacyPolicy from './pages/PrivacyPolicy.tsx' -import TermsAndConditions from './pages/TermsAndConditions.tsx' +import FeaturesPage from './pages/FeaturesPage.tsx' + function App() { return (
@@ -35,8 +34,8 @@ function App() { } /> } /> } /> - } /> - } /> + } /> + {/* Public Routes */} } /> diff --git a/src/index.css b/src/index.css index 1a31f79d..d56751e1 100644 --- a/src/index.css +++ b/src/index.css @@ -24,6 +24,87 @@ .animate-loading-bar { animation: loading 0.8s ease infinite; } + + @keyframes fadeInUp { + 0% { + opacity: 0; + transform: translateY(30px); + } + 100% { + opacity: 1; + transform: translateY(0); + } + } + + @keyframes fadeIn { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } + } + + @keyframes slideInLeft { + 0% { + opacity: 0; + transform: translateX(-30px); + } + 100% { + opacity: 1; + transform: translateX(0); + } + } + + @keyframes slideInRight { + 0% { + opacity: 0; + transform: translateX(30px); + } + 100% { + opacity: 1; + transform: translateX(0); + } + } + + .animate-fade-in-up { + animation: fadeInUp 0.6s ease-out; + } + + .animate-fade-in { + animation: fadeIn 0.5s ease-out; + } + + .animate-slide-in-left { + animation: slideInLeft 0.6s ease-out; + } + + .animate-slide-in-right { + animation: slideInRight 0.6s ease-out; + } +} + +/* Smooth scrolling */ +html { + scroll-behavior: smooth; +} + +/* Custom scrollbar */ +::-webkit-scrollbar { + width: 12px; +} + +::-webkit-scrollbar-track { + background: #0f172a; +} + +::-webkit-scrollbar-thumb { + background: #334155; + border-radius: 6px; +} + +::-webkit-scrollbar-thumb:hover { + background: #475569; } .reveal { @@ -35,4 +116,10 @@ .reveal.visible { opacity: 1; transform: translateY(0); +} + +/* Focus visible for accessibility */ +*:focus-visible { + outline: 2px solid #06b6d4; + outline-offset: 2px; } \ No newline at end of file diff --git a/src/pages/FeaturesPage.tsx b/src/pages/FeaturesPage.tsx new file mode 100644 index 00000000..4becf995 --- /dev/null +++ b/src/pages/FeaturesPage.tsx @@ -0,0 +1,187 @@ +import { Users, MessageSquare, Zap, Code2, Rocket, Globe, ArrowRight } from 'lucide-react'; + +const FeaturesPage = () => { + return ( +
+ {/* Hero Section */} +
+ {/* Animated gradient background */} +
+ + {/* Grid pattern */} +
+ +
+
+
+ + Features +
+

+ Everything You Need to Thrive +

+

+ A complete ecosystem for developers to collaborate, learn, and grow together +

+
+
+
+ + {/* Features Grid */} +
+
+
+ {[ + { + icon: Users, + title: "Join Communities", + description: "Connect with like-minded developers in communities focused on specific technologies and interests. Share knowledge, collaborate on projects, and build lasting professional relationships.", + color: "cyan", + features: [ + "Technology-specific groups", + "Private and public communities", + "Community moderation tools", + "Member rankings and badges" + ] + }, + { + icon: MessageSquare, + title: "Real-time Chat", + description: "Instant messaging, voice channels, and collaborative coding sessions. Stay connected with your team and community members in real-time.", + color: "blue", + features: [ + "Direct messaging", + "Group conversations", + "File sharing", + "Code snippet formatting" + ] + }, + { + icon: Code2, + title: "Share & Learn", + description: "Post code snippets, ask questions, and learn from experienced developers. Get feedback on your code and help others grow.", + color: "purple", + features: [ + "Syntax-highlighted code blocks", + "Q&A discussions", + "Tutorial sharing", + "Code reviews" + ] + }, + { + icon: Zap, + title: "Discover Events", + description: "Find hackathons, meetups, and tech events to expand your network. Stay updated with the latest tech events in your area and beyond.", + color: "emerald", + features: [ + "Local and virtual events", + "RSVP and calendar integration", + "Event notifications", + "Post-event networking" + ] + }, + { + icon: Rocket, + title: "Build Projects", + description: "Collaborate on open source projects and bring your ideas to life. Find team members, showcase your work, and contribute to the community.", + color: "orange", + features: [ + "Project showcases", + "Collaboration tools", + "Git integration", + "Project roadmaps" + ] + }, + { + icon: Globe, + title: "Global Network", + description: "Connect with developers worldwide and build a diverse professional network. Learn from different perspectives and expand your horizons.", + color: "pink", + features: [ + "International community", + "Multi-language support", + "Time zone friendly", + "Cultural exchange programs" + ] + } + ].map((feature, index) => { + const Icon = feature.icon; + const colorClasses: Record = { + cyan: "from-cyan-500/20 to-cyan-600/10 text-cyan-400", + blue: "from-blue-500/20 to-blue-600/10 text-blue-400", + purple: "from-purple-500/20 to-purple-600/10 text-purple-400", + emerald: "from-emerald-500/20 to-emerald-600/10 text-emerald-400", + orange: "from-orange-500/20 to-orange-600/10 text-orange-400", + pink: "from-pink-500/20 to-pink-600/10 text-pink-400" + }; + + return ( +
+
+ +
+
+ +
+ +
+

+ {feature.title} +

+ +

+ {feature.description} +

+
+ +
    + {feature.features.map((item, i) => ( +
  • + + {item} +
  • + ))} +
+
+
+ ); + })} +
+
+
+ + {/* CTA Section */} +
+
+
+

+ Ready to Get Started? +

+

+ Join thousands of developers who are already using DevConnect to build amazing things +

+ +
+
+
+
+ ); +}; + +export default FeaturesPage; diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 6d0e645d..648e83d0 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,13 +1,10 @@ import PostList from '../components/PostList'; -import GlobalSearch from '../components/GlobalSearch'; -import { Plus } from 'lucide-react'; +import { Plus, Users, MessageSquare, Zap, Code2, Rocket, Globe, Sparkles, ArrowRight } from 'lucide-react'; import { Link } from 'react-router-dom'; import { useEffect, useState } from "react"; const Home = () => { - const text = - "Share ideas, build together, connect with developers worldwide..."; - + const text = "Share ideas, build together, connect with developers worldwide..."; const [displayText, setDisplayText] = useState(""); const [index, setIndex] = useState(0); const [isDeleting, setIsDeleting] = useState(false); @@ -16,18 +13,15 @@ const Home = () => { let timeout = null; if (!isDeleting && index < text.length) { - // Typing timeout = setTimeout(() => { setDisplayText(text.slice(0, index + 1)); setIndex((prev) => prev + 1); }, 55); } else if (!isDeleting && index === text.length) { - // Pause after typing timeout = setTimeout(() => { setIsDeleting(true); }, 1200); } else if (isDeleting && index > 0) { - // Deleting timeout = setTimeout(() => { setDisplayText(text.slice(0, index - 1)); setIndex((prev) => prev - 1); @@ -36,6 +30,7 @@ const Home = () => { setIsDeleting(false); setDisplayText(""); } + return () => { if (timeout) clearTimeout(timeout); }; @@ -43,68 +38,171 @@ const Home = () => { return (
- {/* Hero Section */} -
-
-
-
-

- DevConnect -

-

- {displayText} - | -

- - {/* Global Search - Hero Feature */} -
- - + {/* Hero Section - Full Screen */} +
+ {/* Animated gradient background */} +
+ + {/* Grid pattern */} +
+ + {/* Floating elements */} +
+
+ +
+
+
+
+ + Welcome to DevConnect
- -
- +

+ + DevConnect + +

+

+ {displayText} + | +

+
+ +
+ - - create post + + Create Post + - explore communities + + Explore Communities
-
-
-
// Connect with developers
-
const developer = {'{}'}
-
skills: ['web', 'mobile', 'ml']
-
ideas: ['innovative', 'scalable']
-
share.build.grow()
+ + {/* Code Card - Improved */} +
+
+
+ devconnect.js +
+ +
+
+ // Connect with developers worldwide +
+ +
+
const developerNetwork = {"{"}
+
+ skills: [ + 'React', + 'Node.js', + 'Python' + ], +
+
+ projects: 42, +
+
+ connections: 128, +
+
{"}"}
+
+ +
+
+ DevConnect + .connect() + ; +
+
+ DevConnect + .grow() + ; +
+
+
+ + {/* Terminal-like footer */} +
+
+
+ Connected to global developer network +
+
- {/* Posts Section */} -
-
-

- ~/recent_posts -

-

- latest updates from the community -

+ {/* Posts Section - Improved */} +
+
+
+
+
+ + Community Feed +
+

+ Latest from the Community +

+

+ Insights, discussions, and updates from developers worldwide +

+
+ + + View all posts + + +
+
+ + {/* CTA Section */} +
+
+
+

+ Ready to Connect? +

+

+ Join thousands of developers who are already collaborating, learning, and growing together +

+
+ + Get Started Free + + + Explore Features + +
+
+
+
) } diff --git a/src/supabase-client.ts b/src/supabase-client.ts index 93092ccd..214db3fe 100644 --- a/src/supabase-client.ts +++ b/src/supabase-client.ts @@ -1,4 +1,5 @@ import { createClient, SupabaseClient } from '@supabase/supabase-js'; +import createMockSupabase from './utils/mockSupabase'; // Read environment variables (do NOT force-cast) const supabaseUrl = import.meta.env.VITE_SUPABASE_URL; @@ -13,23 +14,15 @@ const isDemoMode = import.meta.env.VITE_DEMO_MODE === 'true'; * - Available when env vars exist and demo mode is disabled * - Null in demo mode or when env vars are missing */ -let supabaseInstance: SupabaseClient | null = null; - -try { - if (!isDemoMode && supabaseUrl && supabaseAnonKey) { - supabaseInstance = createClient(supabaseUrl, supabaseAnonKey, { +export const supabase: SupabaseClient | null = + !isDemoMode && supabaseUrl && supabaseAnonKey + ? createClient(supabaseUrl, supabaseAnonKey, { auth: { persistSession: true, autoRefreshToken: true, }, - }); - } -} catch (error) { - console.warn('Supabase client initialization failed, using mock data:', error); - supabaseInstance = null; -} - -export const supabase = supabaseInstance; + }) + : createMockSupabase(); /** * Helper flag to check if backend is available diff --git a/src/utils/mockSupabase.ts b/src/utils/mockSupabase.ts new file mode 100644 index 00000000..fb0e6f5b --- /dev/null +++ b/src/utils/mockSupabase.ts @@ -0,0 +1,98 @@ + +import { SupabaseClient } from '@supabase/supabase-js'; + +const logMockWarning = (method: string) => { + console.warn(`[Supabase Mock] ${method} called. Backend is not verified/connected. See README.md`); +}; + +// Create a proxy that logs warnings for any property verification +const createMockSupabase = (): SupabaseClient => { + console.error("SUPABASE CLIENT IS MISSING ENV VARS: VITE_SUPABASE_URL or VITE_SUPABASE_ANON_KEY. Falling back to Mock Client."); + + // Minimal mock implementation to prevent crashes + const mockClient: any = { + auth: { + getSession: async () => { + logMockWarning("auth.getSession"); + return { data: { session: null }, error: null }; + }, + onAuthStateChange: (_callback: any) => { + logMockWarning("auth.onAuthStateChange"); + // Immediately return a subscription object + return { data: { subscription: { unsubscribe: () => {} } } }; + }, + signInWithOAuth: async () => { + logMockWarning("auth.signInWithOAuth"); + alert("Authentication is disabled in mock mode. Please set up your .env file."); + return { error: { message: "Mock Sign In Error" } }; + }, + signInWithPassword: async () => { + logMockWarning("auth.signInWithPassword"); + alert("Authentication is disabled in mock mode. Please set up your .env file."); + return { error: { message: "Mock Sign In Error" } }; + }, + signUp: async () => { + logMockWarning("auth.signUp"); + return { error: { message: "Mock Sign Up Error" } }; + }, + signOut: async () => { + logMockWarning("auth.signOut"); + return { error: null }; + }, + resetPasswordForEmail: async () => { + return { error: { message: "Mock Reset Password Error" } }; + }, + updateUser: async () => { + return { error: { message: "Mock Update User Error" } }; + }, + }, + // We can use a Proxy for 'from' to return a chainable mock object + from: (table: string) => { + logMockWarning(`from('${table}')`); + return { + select: (columns: string = '*') => { + return { + order: (column: string, options?: any) => { + return Promise.resolve({ data: [], error: null }); + }, + eq: (column: string, value: any) => { + return Promise.resolve({ data: [], error: null }); + }, + single: () => { + return Promise.resolve({ data: null, error: {message: "Mock Data Not Found"} }); + }, + insert: () => { + return Promise.resolve({data: null, error: {message: "Mock Insert Failed"}}); + }, + update: () => { + return Promise.resolve({data: null, error: {message: "Mock Update Failed"}}); + }, + delete: () => { + return Promise.resolve({data: null, error: {message: "Mock Delete Failed"}}); + } + } + }, + insert: () => Promise.resolve({ data: null, error: { message: "Mock Insert Failed" } }), + update: () => Promise.resolve({ data: null, error: { message: "Mock Update Failed" } }), + delete: () => Promise.resolve({ data: null, error: { message: "Mock Delete Failed" } }), + }; + }, + channel: (name: string) => { + logMockWarning(`channel('${name}')`); + return { + on: () => ({ subscribe: () => {} }), + subscribe: () => {} + } + }, + storage: { + from: (bucket: string) => ({ + upload: () => Promise.resolve({data: null, error: {message: "Mock Upload Failed"}}), + getPublicUrl: (path: string) => ({data: { publicUrl: "" }}) + }) + } + }; + + return mockClient as SupabaseClient; +}; + +export default createMockSupabase;