// full-stack web designer

Ioannis Kaperdas.

I design and build high-performance digital products, web applications, and brand websites using Next.js, React, and TypeScript—from strategy and wireframes to production deployment.

available for new projectsathens, greece · remote worldwide

01Selected work

Things I've built

A few recent projects — the problem, what I shipped, and what changed.

~/lost-hotels-of-greece
L
001

Non-profit digital archive · 2026

Lost Hotels of Greece

problem
Greece's 20th-century grand hotels — Belle Époque seafront palaces, interwar landmarks, the modernist state Xenia network — are being demolished or left to decay. Their histories are fragmented across unreliable, increasingly AI-muddied sources, with no map-based way for the public to explore them.
built
An independent, source-verified, bilingual (EL/EN) archive in React 19 + TypeScript + Vite. Explorable by interactive Leaflet map, architectural style, region and a chronological lifespan timeline — with an AI “historic archivist” (Groq / Llama 3.3) grounded in the cited record, not invented detail.
result
A single, museum-grade home for 12 documented lost hotels and growing — every claim traceable to reputable sources, every image public-domain or CC with full attribution.

12 verified hotels

  • React 19
  • TypeScript
  • Leaflet
  • Groq AI
  • EL / EN
Infinite Impressions × Cookies screenshot
002

AI compliance console · 2026

Infinite Impressions × Cookies

problem
Cookie-consent banners sit in a no-win zone: privacy law (GDPR, CPRA, Consent Mode v2) demands fair, transparent consent while teams chase opt-ins — so the web is full of dark patterns, trackers firing before consent, and inaccessible banners. Most teams can't even tell if theirs is compliant.
built
An AI console that turns that uncertainty into action across five modules: a Trust Auditor that scores any URL and emits copy-pasteable code fixes, an AI banner redesigner with live preview and React/HTML export, a script-load timeline inspector, regional consent analytics, and a privacy consultant tuned on EDPB/CNIL/CCPA guidance. React 19 + Vite + Tailwind v4.
result
A stark, editorial, WCAG-AA console with real Recharts data-viz — and a JS bundle trimmed from ~1057 kB to ~216 kB along the way.

1057 → 216 kB

  • React 19
  • Vite
  • Tailwind v4
  • Recharts
  • AI
MailSentinel screenshot
003

Explainable spam ML · 2026

MailSentinel

problem
Spam and phishing tools are black boxes — most “detectors” are hand-written if/else rules with no honest metrics, demos make you log into Gmail before you see anything, and the public spam corpora are 20 years old.
built
A real classifier (TF-IDF + logistic regression, 97.7% accuracy, 0.997 ROC-AUC) built as a glass box: each word's weight drives inline red/green highlighting and a ranked “why” panel. Inference runs client-side — pasted email never leaves the device — with a Python training pipeline and a parity test matching the TypeScript inference to machine epsilon. Next.js 16 + TypeScript.
result
A login-free, privacy-by-design demo you try in one click, with an open model card and modern-mail domain adaptation so today's email scores correctly. Optional read-only Gmail/Outlook OAuth.

97.7% accuracy

  • Next.js 16
  • TypeScript
  • scikit-learn
  • Explainable ML
02Code

Code I'm working on lately

Patterns I reach for on real work — each solves a problem you'll recognise. Pick one to read it.

Modal.tsx

Modal dialogs that trap focus and restore it — without a UI library.

View on GitHub →
// Problem: accessible modal dialogs that trap focus and restore it on close,
// without pulling in a whole UI library.
import { useEffect, useRef } from "react";

export function Modal({ open, onClose, title, children }: {
  open: boolean;
  onClose: () => void;
  title: string;
  children: React.ReactNode;
}) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!open) return;
    const previouslyFocused = document.activeElement as HTMLElement | null;
    const focusables = ref.current!.querySelectorAll<HTMLElement>(
      'a[href], button:not([disabled]), input, [tabindex]:not([tabindex="-1"])',
    );
    focusables[0]?.focus();

    function onKeyDown(e: KeyboardEvent) {
      if (e.key === "Escape") return onClose();
      if (e.key !== "Tab" || focusables.length === 0) return;
      const first = focusables[0];
      const last = focusables[focusables.length - 1];
      // Wrap focus so Tab never escapes the dialog.
      if (e.shiftKey && document.activeElement === first) {
        e.preventDefault();
        last.focus();
      } else if (!e.shiftKey && document.activeElement === last) {
        e.preventDefault();
        first.focus();
      }
    }

    document.addEventListener("keydown", onKeyDown);
    return () => {
      document.removeEventListener("keydown", onKeyDown);
      previouslyFocused?.focus(); // restore focus to the trigger element
    };
  }, [open, onClose]);

  if (!open) return null;
  return (
    <div className="overlay" onClick={onClose}>
      <div
        ref={ref}
        role="dialog"
        aria-modal="true"
        aria-label={title}
        onClick={(e) => e.stopPropagation()}
      >
        {children}
      </div>
    </div>
  );
}
03About

I build the whole thing

I'm Ioannis Kaperdas, a freelance web developer with an MSc in IT. I design and build websites and web applications end to end — from the first wireframe to a production deploy.

I care about the things that make software actually good: fast load times, accessible markup, typed and maintainable code, and clear communication along the way — not jargon.

Tools are means to an end. I pick the right ones for the job and keep the codebase something the next person (often you) can live with.

what I do

  • Web apps & dashboards
  • /Marketing & landing sites
  • /Performance & SEO
  • /Design → code
based in
Athens, Greece · Remote worldwide
stack
TypeScript · React · Next.js
working with
Startups, agencies & founders

// toolkit

  • TypeScript
  • React
  • Next.js
  • Node.js
  • Tailwind CSS
  • PostgreSQL
  • REST & GraphQL
  • Figma → Code
  • Web Vitals
  • Vercel / CI
04Contact

Let's work together

Have something in mind, or just want to chat? Tell me about it — I'll reply within a day.