project init
This commit is contained in:
62
frontend/lib/auth-context.tsx
Normal file
62
frontend/lib/auth-context.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
"use client"
|
||||
|
||||
import { createContext, useContext, useState, useEffect, type ReactNode } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
|
||||
interface AuthContextType {
|
||||
isAuthenticated: boolean
|
||||
isLoading: boolean
|
||||
login: (email: string, password: string) => Promise<boolean>
|
||||
logout: () => void
|
||||
}
|
||||
|
||||
const AuthContext = createContext<AuthContextType | null>(null)
|
||||
|
||||
// Mock credentials - replace with real API auth
|
||||
const MOCK_CREDENTIALS = {
|
||||
email: "admin@atticl.com",
|
||||
password: "admin123",
|
||||
}
|
||||
|
||||
export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
// Check for existing session
|
||||
const session = localStorage.getItem("atticl_admin_session")
|
||||
if (session === "authenticated") {
|
||||
setIsAuthenticated(true)
|
||||
}
|
||||
setIsLoading(false)
|
||||
}, [])
|
||||
|
||||
const login = async (email: string, password: string): Promise<boolean> => {
|
||||
// Mock API call - replace with real auth
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
if (email === MOCK_CREDENTIALS.email && password === MOCK_CREDENTIALS.password) {
|
||||
localStorage.setItem("atticl_admin_session", "authenticated")
|
||||
setIsAuthenticated(true)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem("atticl_admin_session")
|
||||
setIsAuthenticated(false)
|
||||
router.push("/admin/login")
|
||||
}
|
||||
|
||||
return <AuthContext.Provider value={{ isAuthenticated, isLoading, login, logout }}>{children}</AuthContext.Provider>
|
||||
}
|
||||
|
||||
export function useAuth() {
|
||||
const context = useContext(AuthContext)
|
||||
if (!context) {
|
||||
throw new Error("useAuth must be used within an AuthProvider")
|
||||
}
|
||||
return context
|
||||
}
|
||||
76
frontend/lib/data-store.tsx
Normal file
76
frontend/lib/data-store.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
"use client"
|
||||
|
||||
import { createContext, useContext, useState, type ReactNode } from "react"
|
||||
import type { Project, StackCategory } from "./types"
|
||||
import { mockProjects, mockStackCategories } from "./mock-data"
|
||||
|
||||
interface DataStore {
|
||||
projects: Project[]
|
||||
stackCategories: StackCategory[]
|
||||
// Project CRUD
|
||||
addProject: (project: Omit<Project, "id">) => void
|
||||
updateProject: (id: string, project: Partial<Project>) => void
|
||||
deleteProject: (id: string) => void
|
||||
// Stack CRUD
|
||||
addStackCategory: (category: Omit<StackCategory, "id">) => void
|
||||
updateStackCategory: (id: string, category: Partial<StackCategory>) => void
|
||||
deleteStackCategory: (id: string) => void
|
||||
}
|
||||
|
||||
const DataStoreContext = createContext<DataStore | null>(null)
|
||||
|
||||
export function DataStoreProvider({ children }: { children: ReactNode }) {
|
||||
const [projects, setProjects] = useState<Project[]>(mockProjects)
|
||||
const [stackCategories, setStackCategories] = useState<StackCategory[]>(mockStackCategories)
|
||||
|
||||
const addProject = (project: Omit<Project, "id">) => {
|
||||
const newProject = { ...project, id: crypto.randomUUID() }
|
||||
setProjects((prev) => [...prev, newProject])
|
||||
}
|
||||
|
||||
const updateProject = (id: string, updates: Partial<Project>) => {
|
||||
setProjects((prev) => prev.map((p) => (p.id === id ? { ...p, ...updates } : p)))
|
||||
}
|
||||
|
||||
const deleteProject = (id: string) => {
|
||||
setProjects((prev) => prev.filter((p) => p.id !== id))
|
||||
}
|
||||
|
||||
const addStackCategory = (category: Omit<StackCategory, "id">) => {
|
||||
const newCategory = { ...category, id: crypto.randomUUID() }
|
||||
setStackCategories((prev) => [...prev, newCategory])
|
||||
}
|
||||
|
||||
const updateStackCategory = (id: string, updates: Partial<StackCategory>) => {
|
||||
setStackCategories((prev) => prev.map((c) => (c.id === id ? { ...c, ...updates } : c)))
|
||||
}
|
||||
|
||||
const deleteStackCategory = (id: string) => {
|
||||
setStackCategories((prev) => prev.filter((c) => c.id !== id))
|
||||
}
|
||||
|
||||
return (
|
||||
<DataStoreContext.Provider
|
||||
value={{
|
||||
projects,
|
||||
stackCategories,
|
||||
addProject,
|
||||
updateProject,
|
||||
deleteProject,
|
||||
addStackCategory,
|
||||
updateStackCategory,
|
||||
deleteStackCategory,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</DataStoreContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useDataStore() {
|
||||
const context = useContext(DataStoreContext)
|
||||
if (!context) {
|
||||
throw new Error("useDataStore must be used within a DataStoreProvider")
|
||||
}
|
||||
return context
|
||||
}
|
||||
91
frontend/lib/mock-data.ts
Normal file
91
frontend/lib/mock-data.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import type { Project, StackCategory } from "./types"
|
||||
|
||||
// Mock data store - will be replaced with API calls
|
||||
export const mockProjects: Project[] = [
|
||||
{
|
||||
id: "1",
|
||||
name: "crowware.com",
|
||||
role: "Co-founder & Backend Lead",
|
||||
description:
|
||||
"A developer tools platform built for teams who ship. I designed and built the core backend infrastructure from scratch.",
|
||||
highlights: [
|
||||
"Distributed API architecture handling 10k+ requests/sec",
|
||||
"PostgreSQL with custom indexing strategy for complex queries",
|
||||
"Event-driven microservices with Redis pub/sub",
|
||||
"Zero-downtime deployments with blue-green strategy",
|
||||
"Comprehensive observability stack (Prometheus, Grafana, OpenTelemetry)",
|
||||
],
|
||||
stack: ["Go", "PostgreSQL", "Redis", "Kubernetes", "Terraform"],
|
||||
website: "https://crowware.com",
|
||||
github: null,
|
||||
featured: true,
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "api-gateway",
|
||||
role: "Creator",
|
||||
description:
|
||||
"High-performance API gateway with rate limiting, auth, and request transformation. Built for internal use, battle-tested in production.",
|
||||
highlights: [],
|
||||
stack: ["Go", "Redis", "Docker"],
|
||||
website: null,
|
||||
github: "#",
|
||||
featured: false,
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "pg-migrate",
|
||||
role: "Creator",
|
||||
description:
|
||||
"Zero-downtime PostgreSQL migration tool. Handles large tables without locking, with automatic rollback support.",
|
||||
highlights: [],
|
||||
stack: ["Python", "PostgreSQL"],
|
||||
website: null,
|
||||
github: "#",
|
||||
featured: false,
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "logpipe",
|
||||
role: "Creator",
|
||||
description: "Structured logging pipeline that routes logs to multiple destinations based on severity and content.",
|
||||
highlights: [],
|
||||
stack: ["Rust", "Kafka"],
|
||||
website: null,
|
||||
github: "#",
|
||||
featured: false,
|
||||
},
|
||||
]
|
||||
|
||||
export const mockStackCategories: StackCategory[] = [
|
||||
{
|
||||
id: "1",
|
||||
title: "Backend",
|
||||
items: ["Go", "Python", "Node.js", "Rust"],
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
title: "Databases",
|
||||
items: ["PostgreSQL", "Redis", "SQLite", "ClickHouse"],
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
title: "Infrastructure",
|
||||
items: ["Docker", "Kubernetes", "Terraform", "AWS"],
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
title: "APIs & Protocols",
|
||||
items: ["REST", "GraphQL", "gRPC", "WebSockets"],
|
||||
},
|
||||
{
|
||||
id: "5",
|
||||
title: "Observability",
|
||||
items: ["Prometheus", "Grafana", "OpenTelemetry", "Sentry"],
|
||||
},
|
||||
{
|
||||
id: "6",
|
||||
title: "Tooling",
|
||||
items: ["Git", "CI/CD", "Make", "Nix"],
|
||||
},
|
||||
]
|
||||
23
frontend/lib/types.ts
Normal file
23
frontend/lib/types.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
export interface Project {
|
||||
id: string
|
||||
name: string
|
||||
role: string
|
||||
description: string
|
||||
highlights: string[]
|
||||
stack: string[]
|
||||
website: string | null
|
||||
github: string | null
|
||||
featured: boolean
|
||||
}
|
||||
|
||||
export interface StackCategory {
|
||||
id: string
|
||||
title: string
|
||||
items: string[]
|
||||
}
|
||||
|
||||
export interface User {
|
||||
id: string
|
||||
email: string
|
||||
name: string
|
||||
}
|
||||
6
frontend/lib/utils.ts
Normal file
6
frontend/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
Reference in New Issue
Block a user