diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index ce5c763..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,31 +0,0 @@ -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Build - run: npm run build - - - name: Verify output exists - run: | - if [ ! -d "out" ]; then - echo "out/ not found" - exit 1 - fi diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 49013a4..b41b103 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,35 +1,53 @@ +name: Deploy to GitHub Pages + on: push: branches: [main] + workflow_dispatch: permissions: - contents: write + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true jobs: - build-deploy: + build: runs-on: ubuntu-latest steps: - - name: Checkout repository + - name: Checkout uses: actions/checkout@v4 - - name: Set up Node.js + - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' - cache: 'npm' + node-version: 22 + cache: npm - name: Install dependencies run: npm ci - - name: Build + - name: Build static site run: npm run build - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 + - name: Configure Pages + uses: actions/configure-pages@v5 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./out - publish_branch: gh-pages - keep_files: false - force_orphan: true - commit_message: 'deploy: ${{ github.sha }}' + path: ./out + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 839715a..1b6f1ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,41 @@ -# Node dependencies +# Dependencies node_modules/ -# Build output -/public -/dist -/build +# Next.js +.next/ +out/ -# Hugo -*.log -*.patch -.hugo_build.lock +# Production +build/ +dist/ -# OS & editor artifacts -.DS_Store +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# TypeScript +*.tsbuildinfo +next-env.d.ts + +# Logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editors +.vscode/ .idea/ *.swp -*~ -*.md~ +*.swo -# Tailwind / PostCSS caches -/.cache/ -assets/css/main.css \ No newline at end of file +# Operating systems +.DS_Store +Thumbs.db + +# Local tooling +.vercel/ +.turbo/ diff --git a/.pi/settings.json b/.pi/settings.json deleted file mode 100644 index aeec640..0000000 --- a/.pi/settings.json +++ /dev/null @@ -1 +0,0 @@ -{\"repoUrl\": \"file:///home/emil/Desktop/Coding/AI/UI_test\"} \ No newline at end of file diff --git a/.ralph/proceed.md b/.ralph/proceed.md deleted file mode 100644 index 1d328d8..0000000 --- a/.ralph/proceed.md +++ /dev/null @@ -1,14 +0,0 @@ -# Task - -Describe your task here. - -## Goals -- Goal 1 -- Goal 2 - -## Checklist -- [ ] Item 1 -- [ ] Item 2 - -## Notes -(Update this as you work) diff --git a/.ralph/proceed.state.json b/.ralph/proceed.state.json deleted file mode 100644 index 4bb28f2..0000000 --- a/.ralph/proceed.state.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "proceed", - "taskFile": ".ralph/proceed.md", - "iteration": 2, - "maxIterations": 50, - "itemsPerIteration": 0, - "reflectEvery": 0, - "reflectInstructions": "REFLECTION CHECKPOINT\n\nPause and reflect on your progress:\n1. What has been accomplished so far?\n2. What's working well?\n3. What's not working or blocking progress?\n4. Should the approach be adjusted?\n5. What are the next priorities?\n\nUpdate the task file with your reflection, then continue working.", - "active": false, - "status": "completed", - "startedAt": "2026-04-29T07:23:46.928Z", - "lastReflectionAt": 0, - "completedAt": "2026-04-29T07:38:48.762Z" -} \ No newline at end of file diff --git a/.relevant_files.txt b/.relevant_files.txt deleted file mode 100644 index bd4d568..0000000 --- a/.relevant_files.txt +++ /dev/null @@ -1,271 +0,0 @@ -./content/_index.md -./package.json -./node_modules/@nodelib/fs.walk/package.json -./node_modules/@nodelib/fs.walk/README.md -./node_modules/@nodelib/fs.scandir/package.json -./node_modules/@nodelib/fs.scandir/README.md -./node_modules/@nodelib/fs.stat/package.json -./node_modules/@nodelib/fs.stat/README.md -./node_modules/@jridgewell/trace-mapping/package.json -./node_modules/@jridgewell/trace-mapping/README.md -./node_modules/@jridgewell/sourcemap-codec/package.json -./node_modules/@jridgewell/sourcemap-codec/README.md -./node_modules/@jridgewell/resolve-uri/package.json -./node_modules/@jridgewell/resolve-uri/README.md -./node_modules/@jridgewell/gen-mapping/package.json -./node_modules/@jridgewell/gen-mapping/README.md -./node_modules/postcss/package.json -./node_modules/postcss/README.md -./node_modules/@alloc/quick-lru/package.json -./node_modules/@alloc/quick-lru/readme.md -./node_modules/browserslist/package.json -./node_modules/browserslist/README.md -./node_modules/caniuse-lite/package.json -./node_modules/caniuse-lite/README.md -./node_modules/tailwindcss/lib/value-parser/README.md -./node_modules/tailwindcss/lib/postcss-plugins/nesting/README.md -./node_modules/tailwindcss/src/value-parser/README.md -./node_modules/tailwindcss/src/postcss-plugins/nesting/README.md -./node_modules/tailwindcss/package.json -./node_modules/tailwindcss/README.md -./node_modules/fraction.js/package.json -./node_modules/fraction.js/CHANGELOG.md -./node_modules/fraction.js/README.md -./node_modules/postcss-value-parser/package.json -./node_modules/postcss-value-parser/README.md -./node_modules/baseline-browser-mapping/package.json -./node_modules/baseline-browser-mapping/README.md -./node_modules/update-browserslist-db/package.json -./node_modules/update-browserslist-db/README.md -./node_modules/nanoid/async/package.json -./node_modules/nanoid/non-secure/package.json -./node_modules/nanoid/url-alphabet/package.json -./node_modules/nanoid/package.json -./node_modules/nanoid/README.md -./node_modules/source-map-js/package.json -./node_modules/source-map-js/README.md -./node_modules/arg/package.json -./node_modules/arg/LICENSE.md -./node_modules/arg/README.md -./node_modules/didyoumean/package.json -./node_modules/didyoumean/README.md -./node_modules/dlv/package.json -./node_modules/dlv/README.md -./node_modules/picocolors/package.json -./node_modules/picocolors/README.md -./node_modules/glob-parent/package.json -./node_modules/glob-parent/README.md -./node_modules/is-glob/package.json -./node_modules/is-glob/README.md -./node_modules/jiti/package.json -./node_modules/jiti/README.md -./node_modules/lilconfig/package.json -./node_modules/lilconfig/readme.md -./node_modules/micromatch/package.json -./node_modules/micromatch/README.md -./node_modules/postcss-import/package.json -./node_modules/postcss-import/README.md -./node_modules/object-hash/package.json -./node_modules/normalize-path/package.json -./node_modules/normalize-path/README.md -./node_modules/postcss-js/package.json -./node_modules/postcss-js/README.md -./node_modules/postcss-load-config/package.json -./node_modules/postcss-load-config/README.md -./node_modules/postcss-nested/package.json -./node_modules/postcss-nested/README.md -./node_modules/postcss-selector-parser/package.json -./node_modules/postcss-selector-parser/API.md -./node_modules/postcss-selector-parser/CHANGELOG.md -./node_modules/postcss-selector-parser/README.md -./node_modules/sucrase/package.json -./node_modules/sucrase/README.md -./node_modules/resolve/test/resolver/symlinked/package/package.json -./node_modules/resolve/test/resolver/browser_field/package.json -./node_modules/resolve/test/resolver/nested_symlinks/mylib/package.json -./node_modules/resolve/test/resolver/baz/package.json -./node_modules/resolve/test/resolver/dot_main/package.json -./node_modules/resolve/test/resolver/dot_slash_main/package.json -./node_modules/resolve/test/resolver/false_main/package.json -./node_modules/resolve/test/resolver/incorrect_main/package.json -./node_modules/resolve/test/resolver/multirepo/packages/package-a/package.json -./node_modules/resolve/test/resolver/multirepo/packages/package-b/package.json -./node_modules/resolve/test/resolver/multirepo/package.json -./node_modules/resolve/test/resolver/invalid_main/package.json -./node_modules/resolve/test/module_dir/zmodules/bbb/package.json -./node_modules/resolve/package.json -./node_modules/resolve/.claude/notes.md -./node_modules/resolve/.github/INCIDENT_RESPONSE_PROCESS.md -./node_modules/resolve/.github/THREAT_MODEL.md -./node_modules/resolve/SECURITY.md -./node_modules/anymatch/package.json -./node_modules/anymatch/README.md -./node_modules/electron-to-chromium/package.json -./node_modules/electron-to-chromium/README.md -./node_modules/node-releases/package.json -./node_modules/node-releases/README.md -./node_modules/braces/package.json -./node_modules/braces/README.md -./node_modules/readdirp/package.json -./node_modules/readdirp/README.md -./node_modules/is-binary-path/package.json -./node_modules/is-binary-path/readme.md -./node_modules/merge2/package.json -./node_modules/merge2/README.md -./node_modules/fill-range/package.json -./node_modules/fill-range/README.md -./node_modules/picomatch/package.json -./node_modules/picomatch/README.md -./node_modules/fastq/package.json -./node_modules/fastq/README.md -./node_modules/fastq/SECURITY.md -./node_modules/to-regex-range/package.json -./node_modules/to-regex-range/README.md -./node_modules/run-parallel/package.json -./node_modules/run-parallel/README.md -./node_modules/reusify/package.json -./node_modules/reusify/README.md -./node_modules/reusify/SECURITY.md -./node_modules/binary-extensions/package.json -./node_modules/binary-extensions/readme.md -./node_modules/is-extglob/package.json -./node_modules/is-extglob/README.md -./node_modules/read-cache/package.json -./node_modules/read-cache/README.md -./node_modules/camelcase-css/package.json -./node_modules/camelcase-css/README.md -./node_modules/cssesc/package.json -./node_modules/cssesc/README.md -./node_modules/pify/package.json -./node_modules/pify/readme.md -./node_modules/util-deprecate/package.json -./node_modules/util-deprecate/README.md -./node_modules/util-deprecate/History.md -./node_modules/es-errors/package.json -./node_modules/es-errors/CHANGELOG.md -./node_modules/es-errors/README.md -./node_modules/is-core-module/package.json -./node_modules/is-core-module/CHANGELOG.md -./node_modules/is-core-module/README.md -./node_modules/supports-preserve-symlinks-flag/package.json -./node_modules/supports-preserve-symlinks-flag/CHANGELOG.md -./node_modules/supports-preserve-symlinks-flag/README.md -./node_modules/path-parse/package.json -./node_modules/path-parse/README.md -./node_modules/hasown/package.json -./node_modules/hasown/CHANGELOG.md -./node_modules/hasown/README.md -./node_modules/function-bind/package.json -./node_modules/function-bind/CHANGELOG.md -./node_modules/function-bind/README.md -./node_modules/function-bind/.github/SECURITY.md -./node_modules/queue-microtask/package.json -./node_modules/queue-microtask/README.md -./node_modules/commander/package.json -./node_modules/commander/CHANGELOG.md -./node_modules/commander/Readme.md -./node_modules/lines-and-columns/package.json -./node_modules/lines-and-columns/README.md -./node_modules/mz/package.json -./node_modules/mz/README.md -./node_modules/mz/HISTORY.md -./node_modules/pirates/package.json -./node_modules/pirates/README.md -./node_modules/tinyglobby/node_modules/fdir/package.json -./node_modules/tinyglobby/node_modules/fdir/README.md -./node_modules/tinyglobby/node_modules/picomatch/package.json -./node_modules/tinyglobby/node_modules/picomatch/README.md -./node_modules/tinyglobby/package.json -./node_modules/tinyglobby/README.md -./node_modules/ts-interface-checker/package.json -./node_modules/ts-interface-checker/README.md -./node_modules/object-assign/package.json -./node_modules/object-assign/readme.md -./node_modules/any-promise/package.json -./node_modules/any-promise/README.md -./node_modules/thenify-all/package.json -./node_modules/thenify-all/README.md -./node_modules/thenify-all/History.md -./node_modules/thenify/package.json -./node_modules/thenify/History.md -./node_modules/thenify/README.md -./node_modules/is-number/package.json -./node_modules/is-number/README.md -./node_modules/escalade/package.json -./node_modules/escalade/readme.md -./node_modules/autoprefixer/lib/hacks/flex-spec.js -./node_modules/autoprefixer/package.json -./node_modules/autoprefixer/README.md -./node_modules/chokidar/node_modules/glob-parent/package.json -./node_modules/chokidar/node_modules/glob-parent/CHANGELOG.md -./node_modules/chokidar/node_modules/glob-parent/README.md -./node_modules/chokidar/package.json -./node_modules/chokidar/README.md -./node_modules/fast-glob/node_modules/glob-parent/package.json -./node_modules/fast-glob/node_modules/glob-parent/CHANGELOG.md -./node_modules/fast-glob/node_modules/glob-parent/README.md -./node_modules/fast-glob/package.json -./node_modules/fast-glob/README.md -./node_modules/postcss-reporter/package.json -./node_modules/postcss-reporter/README.md -./node_modules/fs-extra/package.json -./node_modules/fs-extra/README.md -./node_modules/pretty-hrtime/package.json -./node_modules/pretty-hrtime/README.md -./node_modules/slash/package.json -./node_modules/slash/readme.md -./node_modules/yargs/helpers/package.json -./node_modules/yargs/package.json -./node_modules/yargs/README.md -./node_modules/graceful-fs/package.json -./node_modules/graceful-fs/README.md -./node_modules/jsonfile/package.json -./node_modules/jsonfile/README.md -./node_modules/universalify/package.json -./node_modules/universalify/README.md -./node_modules/thenby/package.json -./node_modules/thenby/README.md -./node_modules/cliui/package.json -./node_modules/cliui/CHANGELOG.md -./node_modules/cliui/README.md -./node_modules/get-caller-file/package.json -./node_modules/get-caller-file/LICENSE.md -./node_modules/get-caller-file/README.md -./node_modules/require-directory/package.json -./node_modules/require-directory/README.markdown -./node_modules/string-width/package.json -./node_modules/string-width/readme.md -./node_modules/y18n/package.json -./node_modules/y18n/CHANGELOG.md -./node_modules/y18n/README.md -./node_modules/yargs-parser/package.json -./node_modules/yargs-parser/CHANGELOG.md -./node_modules/yargs-parser/README.md -./node_modules/strip-ansi/package.json -./node_modules/strip-ansi/readme.md -./node_modules/wrap-ansi/package.json -./node_modules/wrap-ansi/readme.md -./node_modules/emoji-regex/package.json -./node_modules/emoji-regex/README.md -./node_modules/is-fullwidth-code-point/package.json -./node_modules/is-fullwidth-code-point/readme.md -./node_modules/ansi-regex/package.json -./node_modules/ansi-regex/readme.md -./node_modules/ansi-styles/package.json -./node_modules/ansi-styles/readme.md -./node_modules/color-convert/package.json -./node_modules/color-convert/CHANGELOG.md -./node_modules/color-convert/README.md -./node_modules/color-name/package.json -./node_modules/color-name/README.md -./node_modules/yaml/browser/package.json -./node_modules/yaml/package.json -./node_modules/yaml/README.md -./node_modules/dependency-graph/specs/dep_graph_spec.js -./node_modules/dependency-graph/package.json -./node_modules/dependency-graph/CHANGELOG.md -./node_modules/dependency-graph/README.md -./node_modules/postcss-cli/node_modules/postcss-load-config/package.json -./node_modules/postcss-cli/node_modules/postcss-load-config/README.md -./node_modules/postcss-cli/package.json -./node_modules/postcss-cli/README.md diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 34e4619..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,17 +0,0 @@ -# IMPORTANT Rules -Always be kind. Prioritize user well-being. - -# Code Quality Principles -Write clear, concise, and efficient code. Avoid unnecessary complexity. - -# Coding Style Preferences -Use consistent 2-space indentation. Use descriptive variable names. Avoid trailing whitespace. - -# Architecture Principles -Favor modular design. Consider scalability early. Prefer simplicity when possible. - -# Development Workflow -Use Git for version control. Write descriptive commit messages. Use pull requests. Run tests before merging. - -# Technical Preferences -Use TypeScript for type safety. Prefer REST over GraphQL for simplicity. Use PostgreSQL for relational data. Use Redis for caching. Use Docker for containerization. \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 681a29c..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,156 +0,0 @@ -# CLAUDE.md — my-project - -> описание проекта - -## Стек - -**Языки:** Go, TypeScript -**Frontend:** React, TypeScript -**Инфраструктура:** Docker, Kubernetes, GitHub Actions, Jenkins -**Стиль кода:** Минимальные зависимости, явные типы (Go type hints + TS strict mode) - ---- - -## Принципы работы агента - -- При неоднозначности в задаче — спрашивай, не угадывай и не двигайся вперёд. -- Предпочитай простейшее рабочее решение. Не создавай абстракций без необходимости. -- Не трогай код, файлы и конфиги вне скоупа текущей задачи. -- Верифицируй результат: запускай тесты, проверяй edge cases до завершения задачи. -- Не ломай существующие тесты ради реализации новой функциональности. - ---- - -## Запрещено - -- Не изменять `.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 ← не изменять без разрешения -``` - ---- - -## Соглашения по коду (Go) - -- Стиль: стандартный `gofmt` / `goimports` -- Линтер: `golangci-lint` — запускать перед коммитом -- Ошибки: всегда оборачивать через `fmt.Errorf("...: %w", err)` -- Логирование: использовать структурированный логгер (slog / zap), не `fmt.Println` -- Конфигурация: через переменные окружения, не хардкодить значения -- Зависимости: минимальные; новую зависимость — только с обоснованием - ---- - -## Соглашения по коду (React / TypeScript) - -- 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 при необходимости - ---- - -## CI/CD соглашения - -### GitHub Actions -- Каждый PR запускает: lint → test → build → docker build -- Образы тегируются: `/:` -- Merge в `main` → автодеплой на staging - -### 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/CONTEXT.md b/CONTEXT.md deleted file mode 100644 index 403b922..0000000 --- a/CONTEXT.md +++ /dev/null @@ -1 +0,0 @@ -[['menu]\n [[menu.main]]\n name = "Resume"\n url = "/resume/', 'weight = 1\n [[menu.main]]\n name = "About"\n url = "/about/', 'weight = 2\n\n[params]\n author = "Emil Shanayev"\n description = "DevOps & Backend Engineer"\n keywords = ["DevOps', 'Backend', 'Go', 'Tailwind', 'Resume'], {'name': 'resume-website', 'private': True, 'scripts': {'build:css': 'postcss assets/css/tailwind.css -o assets/css/main.css', 'build': 'npm run build:css && hugo --minify', 'lint:md': "markdownlint '**/*.md' --config .markdownlint.json || echo 'No markdownlint config'", 'lint:html': "htmlhint 'public/**/*.html' || echo 'No HTML output yet'"}, 'devDependencies': {'autoprefixer': '^10.5.0', 'postcss': '^8.5.12', 'postcss-cli': '^11.0.1', 'tailwindcss': '^3.4.4', 'markdownlint-cli': '^0.35.0', 'htmlhint': '^1.2.0'}}] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ffaec0a --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# Emil Shanayev — Portfolio + +Updated static portfolio based on the original `Emil_Shanayev_Resume` repository. + +## Local development + +```bash +npm install +npm run dev +``` + +Open `http://localhost:3000`. + +## Production build + +```bash +npm run build +``` + +The static export is written to `out/`. + +## GitHub Pages + +The project is preconfigured for: + +`https://emil28092005.github.io/Emil_Shanayev_Resume/` + +Push the project to the `main` branch, then select **Settings → Pages → Source → GitHub Actions**. The included workflow builds and deploys the static export automatically. diff --git a/app/globals.css b/app/globals.css index b7a0d45..ba58f76 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,107 +1,83 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import url('https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Manrope:wght@400;500;600;700&display=swap'); -: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); } +:root { --ink:#171914; --paper:#f2f0e9; --acid:#d7ff3f; --muted:#77796f; --line:#c8c7be; --dark:#20231c; } +* { box-sizing:border-box; } +html { scroll-behavior:smooth; } +body { margin:0; background:var(--paper); color:var(--ink); font-family:'Manrope',sans-serif; } +a { color:inherit; text-decoration:none; } +.shell { width:min(1180px, calc(100% - 48px)); margin-inline:auto; } +.nav { height:86px; display:flex; align-items:center; justify-content:space-between; border-bottom:1px solid var(--line); } +.mark { font:600 17px 'DM Mono',monospace; letter-spacing:-.04em; } +.mark span { color:var(--muted); font-weight:300; } +.nav nav { display:flex; gap:34px; font:400 12px 'DM Mono',monospace; text-transform:uppercase; letter-spacing:.08em; } +.nav nav a:hover { box-shadow:inset 0 -7px var(--acid); } +.hero { min-height:760px; padding:84px 0 70px; position:relative; border-bottom:1px solid var(--line); } +.hero-kicker { float:right; max-width:290px; font:400 11px/1.5 'DM Mono',monospace; text-transform:uppercase; letter-spacing:.06em; color:var(--muted); display:flex; gap:10px; } +.pulse { width:8px; height:8px; margin-top:4px; background:#65b741; border-radius:50%; box-shadow:0 0 0 5px rgba(101,183,65,.12); flex:none; } +.eyebrow { font:400 11px 'DM Mono',monospace; text-transform:uppercase; letter-spacing:.15em; color:var(--muted); } +.hero h1 { font-size:clamp(70px,11.5vw,164px); line-height:.82; letter-spacing:-.085em; margin:108px 0 26px -8px; font-weight:600; } +.hero h2 { max-width:760px; font-size:clamp(28px,4.2vw,58px); line-height:1.03; letter-spacing:-.05em; margin:0 0 32px; font-weight:500; } +.hero-copy { width:min(620px,75%); margin-left:26%; color:#55584f; font-size:16px; line-height:1.75; } +.hero-actions { margin:42px 0 0 26%; display:flex; gap:10px; } +.button { padding:14px 18px; border:1px solid var(--ink); font:500 11px 'DM Mono',monospace; text-transform:uppercase; display:flex; gap:26px; justify-content:space-between; } +.button.primary { background:var(--ink); color:white; } +.button:hover { background:var(--acid); color:var(--ink); } +.hero-index { position:absolute; right:0; bottom:70px; font:300 11px 'DM Mono',monospace; color:var(--muted); } +.section-heading { display:flex; justify-content:space-between; align-items:flex-end; padding:23px 0; border-bottom:1px solid var(--ink); } +.section-heading p { margin:0; font:500 12px 'DM Mono',monospace; text-transform:uppercase; letter-spacing:.11em; } +.section-heading span { font:300 11px 'DM Mono',monospace; color:var(--muted); } +.capabilities,.work,.tools,.about { padding-top:100px; } +.cap-grid { display:grid; grid-template-columns:repeat(3,1fr); } +.cap-card { padding:42px 30px 36px 0; min-height:320px; border-right:1px solid var(--line); } +.cap-card + .cap-card { padding-left:30px; } +.cap-card:last-child { border-right:0; } +.cap-number { font:300 11px 'DM Mono',monospace; color:var(--muted); } +.cap-card h3 { font-size:24px; margin:54px 0 16px; letter-spacing:-.035em; } +.cap-card p { color:#65675f; font-size:14px; line-height:1.7; min-height:74px; } +.tag-list { display:flex; flex-wrap:wrap; gap:7px; margin-top:24px; } +.tag-list span { font:400 10px 'DM Mono',monospace; border:1px solid var(--line); padding:6px 8px; color:#55584f; } +.project { display:grid; grid-template-columns:160px minmax(0,1fr) 150px; gap:34px; padding:52px 0; border-bottom:1px solid var(--line); transition:padding .2s; } +.project:hover { padding-left:12px; } +.project-meta span { font:300 11px 'DM Mono',monospace; color:var(--muted); } +.project-meta p { font:400 10px/1.5 'DM Mono',monospace; text-transform:uppercase; color:var(--muted); margin-top:60px; } +.project-body h3 { margin:0 0 18px; font-size:clamp(30px,4vw,52px); letter-spacing:-.055em; font-weight:500; } +.project-body > p { max-width:720px; color:#5d6057; line-height:1.75; margin:0; } +.project-body ul { display:grid; grid-template-columns:1fr 1fr; padding:0; margin:26px 0 0; list-style:none; gap:9px 20px; } +.project-body li { font:400 11px 'DM Mono',monospace; } +.project-body li::before { content:'—'; color:var(--muted); margin-right:9px; } +.project-links { display:flex; align-items:flex-end; justify-content:flex-end; flex-direction:column; gap:10px; } +.project-links a { width:100%; display:flex; justify-content:space-between; padding:11px 0; border-bottom:1px solid var(--ink); font:400 10px 'DM Mono',monospace; text-transform:uppercase; } +.project-links a:hover { background:var(--acid); padding-inline:8px; } +.tool-grid { display:grid; grid-template-columns:1fr 1fr; } +.tool-grid a { min-height:130px; border-bottom:1px solid var(--line); padding:26px 0; display:flex; justify-content:space-between; gap:30px; } +.tool-grid a:nth-child(odd) { padding-right:30px; border-right:1px solid var(--line); } +.tool-grid a:nth-child(even) { padding-left:30px; } +.tool-grid strong { font-size:18px; } +.tool-grid p { color:var(--muted); font-size:12px; margin:9px 0 0; } +.tool-grid a:hover strong { box-shadow:inset 0 -8px var(--acid); } +.education { display:grid; grid-template-columns:160px 1fr 1fr; gap:34px; padding:48px 0 100px; } +.education > span { font:300 11px 'DM Mono',monospace; color:var(--muted); } +.education h3 { margin:0 0 8px; font-size:22px; } +.education p { margin:0; color:var(--muted); line-height:1.6; } +.education-note { font-size:13px; } +.footer { background:var(--dark); color:#f3f1e9; width:100%; max-width:none; padding:90px max(24px,calc((100% - 1180px)/2)) 32px; margin-top:30px; } +.footer .eyebrow { color:#a4a69c; } +.footer h2 { font-size:clamp(45px,7vw,96px); line-height:.98; letter-spacing:-.065em; font-weight:500; margin:48px 0 80px; } +.footer h2 em { color:var(--acid); font-style:normal; } +.contact-grid { border-top:1px solid #484b42; } +.contact-grid a { display:grid; grid-template-columns:120px 1fr 30px; padding:22px 0; border-bottom:1px solid #484b42; align-items:center; } +.contact-grid span { font:400 10px 'DM Mono',monospace; text-transform:uppercase; color:#92958a; } +.contact-grid strong { font-weight:400; } +.contact-grid a:hover strong { color:var(--acid); } +.footer-bottom { display:flex; justify-content:space-between; padding-top:60px; color:#787b71; font:300 9px 'DM Mono',monospace; text-transform:uppercase; } +@media (max-width:760px) { + .shell { width:min(100% - 28px,1180px); } + .nav { height:70px; }.nav nav { gap:14px; }.nav nav a:nth-child(2){display:none} + .hero { min-height:auto; padding:55px 0 60px; }.hero-kicker { float:none; margin-bottom:70px; }.hero h1 { margin-top:0; font-size:19vw; }.hero h2 { font-size:36px; } + .hero-copy,.hero-actions { width:100%; margin-left:0; }.hero-copy { margin-top:30px; }.hero-actions { flex-direction:column; }.hero-index { display:none; } + .section-heading span { display:none; }.capabilities,.work,.tools,.about { padding-top:70px; } + .cap-grid { grid-template-columns:1fr; }.cap-card,.cap-card + .cap-card { border-right:0; border-bottom:1px solid var(--line); padding:34px 0; min-height:0; }.cap-card h3 { margin-top:28px; }.cap-card p { min-height:0; } + .project { grid-template-columns:1fr; gap:20px; padding:38px 0; }.project:hover { padding-left:0; }.project-meta { display:flex; justify-content:space-between; }.project-meta p { margin:0; }.project-body ul { grid-template-columns:1fr; }.project-links { align-items:flex-start; }.project-links a { width:150px; } + .tool-grid { grid-template-columns:1fr; }.tool-grid a:nth-child(n) { border-right:0; padding:24px 0; } + .education { grid-template-columns:1fr; gap:20px; padding-bottom:70px; }.contact-grid a { grid-template-columns:80px 1fr 20px; }.contact-grid strong { font-size:12px; overflow-wrap:anywhere; }.footer-bottom { gap:20px; }.footer-bottom span:last-child { text-align:right; } } diff --git a/app/layout.tsx b/app/layout.tsx index 9deaaf4..8e7344d 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,25 +2,15 @@ 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'], + title: 'Emil Shanayev — AI Systems & Scientific Software', + description: 'Portfolio of Emil Shanayev: AI-native systems, scientific software, graphics and infrastructure.', authors: [{ name: 'Emil Shanayev' }], } -export default function RootLayout({ children }: { children: React.ReactNode }) { +export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { return ( - - - - - - {children} + {children} ) } diff --git a/app/page.tsx b/app/page.tsx index ef8f6a5..13564a3 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,19 +1,115 @@ -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' +import { resume } from '@/data/resume' + +const Arrow = () => export default function Home() { return ( - <> -