From 727996503e04853663450c381f9360feca491db5 Mon Sep 17 00:00:00 2001 From: emil28092005 Date: Thu, 30 Apr 2026 04:15:07 +0300 Subject: [PATCH] feat: rewrite site as Next.js 14 portfolio with terminal aesthetic Replaces Hugo site with a Next.js App Router (TypeScript) build. Tailwind CSS custom terminal palette, Framer Motion scroll reveals, JetBrains Mono font, scanline/vignette overlays, typing animation. Sections: Hero, Skills, Projects, Contact. Content driven from data/resume.ts. Deploy workflow updated for static export to gh-pages. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/deploy.yml | 18 +- CLAUDE.md | 169 ++++++-- app/globals.css | 107 +++++ app/layout.tsx | 26 ++ app/page.tsx | 19 + components/Contact.tsx | 58 +++ components/Hero.tsx | 74 ++++ components/Nav.tsx | 49 +++ components/Projects.tsx | 80 ++++ components/Reveal.tsx | 27 ++ components/SectionLabel.tsx | 19 + components/Skills.tsx | 45 ++ components/TypingText.tsx | 63 +++ data/resume.ts | 112 +++++ next-env.d.ts | 5 + next.config.mjs | 13 + package-lock.json | 789 +++++++++++++++++++---------------- package.json | 26 +- tailwind.config.js | 56 ++- tailwind.config.ts | 59 +++ tsconfig.json | 23 + 21 files changed, 1392 insertions(+), 445 deletions(-) create mode 100644 app/globals.css create mode 100644 app/layout.tsx create mode 100644 app/page.tsx create mode 100644 components/Contact.tsx create mode 100644 components/Hero.tsx create mode 100644 components/Nav.tsx create mode 100644 components/Projects.tsx create mode 100644 components/Reveal.tsx create mode 100644 components/SectionLabel.tsx create mode 100644 components/Skills.tsx create mode 100644 components/TypingText.tsx create mode 100644 data/resume.ts create mode 100644 next-env.d.ts create mode 100644 next.config.mjs create mode 100644 tailwind.config.ts create mode 100644 tsconfig.json diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ae1594c..49013a4 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -12,30 +12,24 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Setup Hugo - uses: peaceiris/actions-hugo@v2 - with: - hugo-version: 'latest' - - - name: Set up Node.js for Tailwindcss + - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '20' + cache: 'npm' - name: Install dependencies run: npm ci - - name: Build CSS asset - run: npm run build:css - - - name: Build Hugo site - run: hugo --minify + - name: Build + run: npm run build - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./out publish_branch: gh-pages keep_files: false force_orphan: true - commit_message: Deploy Hugo site + commit_message: 'deploy: ${{ github.sha }}' diff --git a/CLAUDE.md b/CLAUDE.md index 3a63842..681a29c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,49 +1,156 @@ -# CLAUDE.md +# CLAUDE.md — my-project -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +> описание проекта -## Project Overview +## Стек -Hugo static resume website for Emil Shanayev (DevOps & Backend Engineer), styled with Tailwind CSS 3.x and deployed to GitHub Pages via GitHub Actions. +**Языки:** Go, TypeScript +**Frontend:** React, TypeScript +**Инфраструктура:** Docker, Kubernetes, GitHub Actions, Jenkins +**Стиль кода:** Минимальные зависимости, явные типы (Go type hints + TS strict mode) -## Commands +--- -```bash -# Local dev server (watches for changes) -hugo server +## Принципы работы агента -# Compile Tailwind CSS only -npm run build:css +- При неоднозначности в задаче — спрашивай, не угадывай и не двигайся вперёд. +- Предпочитай простейшее рабочее решение. Не создавай абстракций без необходимости. +- Не трогай код, файлы и конфиги вне скоупа текущей задачи. +- Верифицируй результат: запускай тесты, проверяй edge cases до завершения задачи. +- Не ломай существующие тесты ради реализации новой функциональности. -# Full production build (CSS + Hugo minified) -npm run build +--- + +## Запрещено + +- Не изменять `.env`, `docker-compose.yml`, `k8s/prod/*` без явного разрешения. +- Не делать `git push --force` ни при каких обстоятельствах. +- Не деплоить в production без явного подтверждения пользователя. +- Не удалять Kubernetes namespaces, PersistentVolumes или secrets без явной команды. +- Не изменять pipeline-конфиги (Jenkinsfile, .github/workflows/*) без обсуждения. + +--- + +## Точки остановки (обязательный checkpoint) + +Агент обязан остановиться и явно спросить разрешение перед: + +- Любыми изменениями в `k8s/prod/*` или `k8s/staging/*` +- Удалением Docker-образов, volumes или сетей +- Изменением RBAC-правил или ServiceAccount'ов +- Ротацией или созданием новых secrets/credentials +- Изменением resource limits/requests на production-сервисах +- Любой операцией, которую нельзя откатить за < 5 минут + +--- + +## Структура проекта + +``` +. +├── cmd/ # точки входа (main.go) +├── internal/ # приватный код приложения +├── pkg/ # публичные пакеты +├── frontend/ # React-приложение (TypeScript) +│ ├── src/ +│ │ ├── components/ +│ │ ├── hooks/ +│ │ └── pages/ +│ └── package.json +├── k8s/ +│ ├── base/ # базовые манифесты +│ ├── staging/ # overlays для staging +│ └── prod/ # overlays для production ← только с разрешения +├── .github/ +│ └── workflows/ # GitHub Actions pipelines +├── Dockerfile +├── docker-compose.yml ← не изменять без разрешения +└── .env ← не изменять без разрешения ``` -CSS must be compiled before Hugo can use it — `npm run build` handles this in the correct order. +--- -## Architecture +## Соглашения по коду (Go) -**Hugo + PostCSS pipeline:** +- Стиль: стандартный `gofmt` / `goimports` +- Линтер: `golangci-lint` — запускать перед коммитом +- Ошибки: всегда оборачивать через `fmt.Errorf("...: %w", err)` +- Логирование: использовать структурированный логгер (slog / zap), не `fmt.Println` +- Конфигурация: через переменные окружения, не хардкодить значения +- Зависимости: минимальные; новую зависимость — только с обоснованием -- `assets/css/tailwind.css` — Tailwind entry point (source); processed by PostCSS → `assets/css/main.css` (generated, not committed) -- `tailwind.config.js` — content glob scans `**/*.{html,js,ts,jsx,md,go,rs}`; dark mode via `class`; custom color palette under `primary`, `secondary`, `dark`, `bg` -- `layouts/` — Hugo HTML templates (currently `_default/` only) -- `content/` — Markdown pages; `_index.md` is the homepage resume content (written in Russian) -- `config.toml` — Hugo site config (author, description, menu entries) +--- -**CI/CD (`.github/workflows/`):** +## Соглашения по коду (React / TypeScript) -- `ci.yml` — runs on PRs to `main`: installs deps, lints Markdown (`markdownlint`) and generated HTML (`htmlhint`), then builds -- `deploy.yml` — runs on push to `main`: builds site and pushes `public/` to `gh-pages` branch via `peaceiris/actions-gh-pages` +- TypeScript strict mode обязателен (`"strict": true` в tsconfig) +- Компоненты: только функциональные, без class components +- Именование: компоненты — `PascalCase`, хуки — `useCamelCase`, файлы — `kebab-case.tsx` +- Стейт: локальный через `useState`/`useReducer`; глобальный — только при явной необходимости +- Пропсы: всегда типизировать через `interface`, не `type` (для расширяемости) +- Эффекты: не использовать `useEffect` для получения данных — использовать React Query / SWR +- Линтер: ESLint + `eslint-plugin-react-hooks` — запускать перед коммитом +- Форматтер: Prettier с конфигом из репозитория — не менять настройки +- Тесты: Vitest + React Testing Library; не тестировать детали реализации, только поведение +- Никаких `any` типов — использовать `unknown` + type guard при необходимости -**Utility directories:** +--- -- `core/user/` — user identity and preference notes consumed by AI tooling -- `templates/` — blank identity/preference templates -- `.pi/` — pi-agent settings (repo URL reference) +## CI/CD соглашения -## Style Preferences +### GitHub Actions +- Каждый PR запускает: lint → test → build → docker build +- Образы тегируются: `/:` +- Merge в `main` → автодеплой на staging -- 2-space indentation -- Descriptive variable names, no trailing whitespace -- TypeScript preferred for any scripting; REST over GraphQL; PostgreSQL/Redis for data +### Jenkins +- Production-деплой только через Jenkins pipeline с ручным approve-шагом +- Rollback через `helm rollback` или `kubectl rollout undo` + +--- + +## Работа с Docker + +- Base image: `gcr.io/distroless/static-debian12` или `alpine:3.x` — не `latest` +- Multi-stage build обязателен для Go-бинарей +- Никаких секретов в ENV инструкциях Dockerfile (использовать BuildKit secrets или runtime env) +- Образы сканировать через `trivy` в CI перед пушем + +--- + +## Работа с Kubernetes + +- Все манифесты через Kustomize (не сырой kubectl apply в production) +- Resource requests/limits — обязательны для каждого контейнера +- Liveness/readiness probes — обязательны +- PodDisruptionBudget — обязателен для stateful сервисов +- Никаких `latest` тегов в манифестах + +--- + +## Тестирование + +- Unit-тесты: `go test ./...` +- Интеграционные тесты: `go test -tags=integration ./...` +- Покрытие Go: цель ≥ 70% для `internal/` +- Frontend тесты: `pnpm test` (Vitest) — запускать из `frontend/` +- Перед завершением задачи: убедиться, что все тесты проходят + +--- + +## Соглашения по коммитам (Conventional Commits) + +``` +feat: новая функциональность +fix: исправление бага +chore: рутинные задачи (зависимости, конфиги) +refactor: рефакторинг без изменения поведения +test: добавление/изменение тестов +ci: изменения в CI/CD пайплайнах +docs: документация +``` + +Примеры: +- `feat(auth): add JWT validation middleware` +- `fix(deploy): correct resource limits for worker pod` +- `ci: add trivy scan step to GitHub Actions` diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..b7a0d45 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,107 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --bg: #0a0a0a; + --card: #0f0f0f; + --amber: #f59e0b; + --green: #22c55e; + --text: #e4e4e7; + --muted: #71717a; + --border: #1c1c1e; + --border2: #27272a; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + scroll-behavior: smooth; + scroll-padding-top: 4rem; +} + +body { + background-color: var(--bg); + color: var(--text); + font-family: 'JetBrains Mono', ui-monospace, monospace; + -webkit-font-smoothing: antialiased; + min-height: 100vh; +} + +/* Scanline overlay */ +body::before { + content: ''; + position: fixed; + inset: 0; + background: repeating-linear-gradient( + 0deg, + transparent, + transparent 3px, + rgba(0, 0, 0, 0.018) 3px, + rgba(0, 0, 0, 0.018) 4px + ); + pointer-events: none; + z-index: 9999; +} + +/* Subtle vignette */ +body::after { + content: ''; + position: fixed; + inset: 0; + background: radial-gradient( + ellipse at center, + transparent 60%, + rgba(0, 0, 0, 0.35) 100% + ); + pointer-events: none; + z-index: 9998; +} + +/* Scrollbar */ +::-webkit-scrollbar { + width: 3px; +} +::-webkit-scrollbar-track { + background: var(--bg); +} +::-webkit-scrollbar-thumb { + background: var(--border2); +} +::-webkit-scrollbar-thumb:hover { + background: var(--muted); +} + +/* Text selection */ +::selection { + background: rgba(245, 158, 11, 0.25); + color: var(--text); +} + +/* Cursor blink */ +@keyframes blink { + 0%, 100% { opacity: 1; } + 50% { opacity: 0; } +} +.cursor-blink { + animation: blink 1.1s step-end infinite; +} + +/* Fade up entrance */ +@keyframes fadeUp { + from { opacity: 0; transform: translateY(14px); } + to { opacity: 1; transform: translateY(0); } +} +.fade-up { + animation: fadeUp 0.55s ease forwards; +} + +/* Draw line */ +@keyframes drawLine { + from { transform: scaleX(0); } + to { transform: scaleX(1); } +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..9deaaf4 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,26 @@ +import type { Metadata } from 'next' +import './globals.css' + +export const metadata: Metadata = { + title: 'Emil Shanayev — DevOps & Backend Engineer', + description: + 'Portfolio of Emil Shanayev — DevOps Engineer and Backend Developer specializing in Python/FastAPI, Kubernetes, Docker, and Linux infrastructure.', + keywords: ['DevOps', 'Backend', 'Python', 'Go', 'Kubernetes', 'Docker', 'FastAPI'], + authors: [{ name: 'Emil Shanayev' }], +} + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + {children} + + ) +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..ef8f6a5 --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,19 @@ +import { Nav } from '@/components/Nav' +import { Hero } from '@/components/Hero' +import { Skills } from '@/components/Skills' +import { Projects } from '@/components/Projects' +import { Contact } from '@/components/Contact' + +export default function Home() { + return ( + <> +