diff --git a/.env.example b/.env.example index 4ffcf7d..d94e783 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ -VITE_APPWRITE_ENDPOINT= -VITE_APPWRITE_PROJECT_ID= -VITE_APPWRITE_PROJECT_NAME= \ No newline at end of file +VITE_APPWRITE_PROJECT_ID = "699ebd17003273658385" +VITE_APPWRITE_PROJECT_NAME = "kajan.meNew project" +VITE_APPWRITE_ENDPOINT = "https://fra.cloud.appwrite.io/v1" + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index aead0d9..f4fd04b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,11 @@ "@appwrite.io/pink-icons": "^1.0.0", "@tailwindcss/vite": "^4.0.14", "appwrite": "^21.2.1", + "lucide-react": "^0.575.0", + "marked": "^17.0.3", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^7.13.1", "tailwindcss": "^4.0.14" }, "devDependencies": { @@ -1974,6 +1977,19 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3823,6 +3839,27 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.575.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.575.0.tgz", + "integrity": "sha512-VuXgKZrk0uiDlWjGGXmKV6MSk9Yy4l10qgVvzGn2AWBx1Ylt0iBexKOAoA6I7JO3m+M9oeovJd3yYENfkUbOeg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/marked": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.3.tgz", + "integrity": "sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -4230,6 +4267,44 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.1.tgz", + "integrity": "sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.1.tgz", + "integrity": "sha512-UJnV3Rxc5TgUPJt2KJpo1Jpy0OKQr0AjgbZzBFjaPJcFOb2Y8jA5H3LT8HUJAiRLlWrEXWHbF1Z4SCZaQjWDHw==", + "license": "MIT", + "dependencies": { + "react-router": "7.13.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -4411,6 +4486,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", diff --git a/package.json b/package.json index 1c89a7c..8e081f0 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,11 @@ "@appwrite.io/pink-icons": "^1.0.0", "@tailwindcss/vite": "^4.0.14", "appwrite": "^21.2.1", + "lucide-react": "^0.575.0", + "marked": "^17.0.3", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^7.13.1", "tailwindcss": "^4.0.14" }, "devDependencies": { diff --git a/src/App.css b/src/App.css deleted file mode 100644 index ffccc3f..0000000 --- a/src/App.css +++ /dev/null @@ -1,20 +0,0 @@ -@import "tailwindcss"; - -summary::-webkit-details-marker { - display: none -} - -.checker-background::before { - content: ""; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-image: linear-gradient(#e6e6e690 1px, transparent 1px), - linear-gradient(90deg, #e6e6e690 1px, transparent 1px); - background-size: 3.7em 3.7em; - mask-image: radial-gradient(ellipse at 50% 40%, black 0%, transparent 55%); - z-index: -1; - background-position-x: center; -} diff --git a/src/App.jsx b/src/App.jsx index 9b4ec1c..a96ff84 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,311 +1,607 @@ -import { useState, useRef, useEffect, useCallback } from "react"; -import "./App.css"; -import { client } from "./lib/appwrite"; -import { AppwriteException } from "appwrite"; -import AppwriteSvg from "../public/appwrite.svg"; -import ReactSvg from "../public/react.svg"; - -function App() { - const [detailHeight, setDetailHeight] = useState(55); - const [logs, setLogs] = useState([]); - const [status, setStatus] = useState("idle"); - const [showLogs, setShowLogs] = useState(false); - - const detailsRef = useRef(null); - - const updateHeight = useCallback(() => { - if (detailsRef.current) { - setDetailHeight(detailsRef.current.clientHeight); - } - }, [logs, showLogs]); +import React, { useEffect, useMemo, useRef, useState } from "react"; +import profileImg from "./assets/profile.jpg"; +import heroLogo from "./assets/profile.jpg"; // ✅ using your profile as the logo above name (change later if you want) +import GitHubProjects from "./GitHubProjects.jsx"; +import BlogSection from "./blog/BlogSection.jsx"; + +const NAME = "KAJAN SIVARAJA"; +const ROLE = "Cyber Security | Blue Team • Pentesting • Secure Coding"; +const TAGLINE = + "I build secure systems, break insecure ones, and translate risk into action."; + +const LINKS = [ + { label: "GitHub", href: "https://github.com/sksivakajan" }, + { label: "LinkedIn", href: "https://linkedin.com/" }, + { label: "Email", href: "mailto:you@example.com" }, +]; + +const SKILLS = [ + { + group: "Security", + items: ["SOC", "SIEM", "Threat Hunting", "Incident Response", "Vulnerability Management"], + }, + { group: "Offense", items: ["Web Pentest", "Recon", "Burp Suite", "OWASP Top 10", "Nmap"] }, + { group: "Dev", items: ["Secure Coding", "React", "Node.js", "Python", "API Security"] }, + { group: "Tools", items: ["Wireshark", "ELK/Splunk", "Git", "Docker", "Linux"] }, +]; + +const CERTS = [ + { name: "BSc (Hons) IT", meta: "Specializing in Cyber Security" }, + { name: "eJPT", meta: "Junior Penetration Tester" }, + { name: "ICCA", meta: "Cybersecurity Certification" }, +]; +function useRevealOnScroll() { useEffect(() => { - updateHeight(); - window.addEventListener("resize", updateHeight); - return () => window.removeEventListener("resize", updateHeight); - }, [updateHeight]); + const els = Array.from(document.querySelectorAll("[data-reveal]")); + const io = new IntersectionObserver( + (entries) => entries.forEach((e) => e.isIntersecting && e.target.classList.add("is-visible")), + { threshold: 0.12 } + ); + els.forEach((el) => io.observe(el)); + return () => io.disconnect(); + }, []); +} + +function clamp(n, a, b) { + return Math.max(a, Math.min(b, n)); +} + +function formatPrompt(cmd) { + return `kaju@security-lab:~$ ${cmd}`; +} + +/* ✅ NEW: Animated hoodie hacker SVG block */ +function HoodieHackerArt() { + return ( + + ); +} + +function Terminal() { + const [history, setHistory] = useState([ + { type: "out", text: "KAJU Terminal v2.6 — Type: help" }, + { type: "out", text: "Tip: try `skills`, `projects`, `certs`, `blog`, `contact`" }, + ]); + const [value, setValue] = useState(""); + const endRef = useRef(null); + + const commands = useMemo( + () => ({ + help: () => [ + "Available commands:", + " - about", + " - skills", + " - projects", + " - certs", + " - blog", + " - contact", + " - clear", + ], + about: () => [TAGLINE, "Focus: security engineering, detection, and practical pentesting."], + skills: () => SKILLS.flatMap((g) => [`${g.group}: ${g.items.join(", ")}`]), + projects: () => ["Projects are auto-loaded from GitHub in the Projects section."], + certs: () => CERTS.map((c) => `• ${c.name} — ${c.meta}`), + blog: () => ["Blog posts live in src/blog/posts/*.md"], + contact: () => [ + "Email: you@example.com", + "GitHub: https://github.com/sksivakajan", + "LinkedIn: https://linkedin.com/", + ], + clear: () => "__CLEAR__", + }), + [] + ); useEffect(() => { - if (!detailsRef.current) return; - detailsRef.current.addEventListener("toggle", updateHeight); + endRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [history]); - return () => { - if (!detailsRef.current) return; - detailsRef.current.removeEventListener("toggle", updateHeight); - }; - }, []); + const run = (cmdRaw) => { + const cmd = cmdRaw.trim(); + if (!cmd) return; + + setHistory((h) => [...h, { type: "in", text: formatPrompt(cmd) }]); + + const key = cmd.split(" ")[0].toLowerCase(); + const fn = commands[key]; - async function sendPing() { - if (status === "loading") return; - setStatus("loading"); - try { - const result = await client.ping(); - const log = { - date: new Date(), - method: "GET", - path: "/v1/ping", - status: 200, - response: JSON.stringify(result), - }; - setLogs((prevLogs) => [log, ...prevLogs]); - setStatus("success"); - } catch (err) { - const log = { - date: new Date(), - method: "GET", - path: "/v1/ping", - status: err instanceof AppwriteException ? err.code : 500, - response: - err instanceof AppwriteException - ? err.message - : "Something went wrong", - }; - setLogs((prevLogs) => [log, ...prevLogs]); - setStatus("error"); + if (!fn) { + setHistory((h) => [...h, { type: "out", text: `Command not found: ${key} (try help)` }]); + return; } - setShowLogs(true); - } + + const res = fn(); + if (res === "__CLEAR__") { + setHistory([{ type: "out", text: "KAJU Terminal v2.6 — Type: help" }]); + return; + } + + setHistory((h) => [...h, ...res.map((t) => ({ type: "out", text: t }))]); + }; return ( -
-
-
-
- {"React +
+
+
+ + + +
+
interactive_shell
+
secure • fast • minimal
+
+ +
+ {history.map((line, idx) => ( +
+ {line.text}
+ ))} +
+
+ +
{ + e.preventDefault(); + run(value); + setValue(""); + }} + > + + setValue(e.target.value)} + placeholder="type a command…" + spellCheck={false} + /> + +
+
+ ); +} + +function ThreatRadar() { + const [level, setLevel] = useState(72); + + useEffect(() => { + const t = setInterval(() => { + setLevel((v) => clamp(v + (Math.random() * 10 - 5), 35, 96)); + }, 1100); + return () => clearInterval(t); + }, []); + + const status = level > 80 ? "ELEVATED" : level > 60 ? "MONITORING" : level > 45 ? "STABLE" : "LOW"; + + return ( +
+
+
+
Threat Radar
+
signal integrity • anomaly awareness
+
+
+
{Math.round(level)}%
+
{status}
+
+
+ +
+
+
+
+ {Array.from({ length: 9 }).map((_, i) => ( + + ))} +
+
+
+ +
+
+ Mode: Adaptive Scan +
+
+ Telemetry: Active +
+
+ Last update: just now +
+
+
+ ); +} + +function Nav() { + return ( +
+ +
+ ); +} + +function Section({ id, title, eyebrow, children }) { + return ( +
+
+
{eyebrow}
+

{title}

+
+ {children} +
+ ); +} + +function Hero() { + return ( +
+
+
+ + Available for internships • projects • research
-
-
-
-
+ + {/* ✅ NEW: logo above your name */} +
+ Kaju logo +
KAJU • Neon Ops
-
-
- {"Appwrite + +

+ {NAME} +

+ +

{ROLE}

+

{TAGLINE}

+ + + +
+ {LINKS.map((l) => ( + + + {l.label} + + ))} +
+ + {/* ✅ NEW: fill empty space with hacker art */} + + +
+
+
01
+
Security mindset
+
+
+
02
+
Hands-on projects
+
+
+
03
+
Fast learning
-
- {status === "loading" ? ( -
-
- - Loading... +
+
+
+ Kajan profile +
+
{NAME}
+
GitHub: sksivakajan
+
Focus: SOC • AppSec • Pentest
- Waiting for connection...
- ) : status === "success" ? ( -

- Congratulations! -

- ) : ( -

- Check connection -

- )} - -

- {status === "success" ? ( - You connected your app successfully. - ) : status === "error" || status === "idle" ? ( - Send a ping to verify the connection - ) : null} -

- - -
- -
+ ); +} + +function Skills() { + return ( +
+ +
+ ); +} -