A premium, production-ready personal portfolio website for Abdusodiqov Abdulaziz, a professional delivery driver working with Largo company. Built with Next.js 15, TypeScript, Tailwind CSS, and Framer Motion β fully in the Uzbek language.
This is a personal portfolio and digital business card for Abdusodiqov Abdulaziz, a 26-year-old professional delivery driver operating under the Largo company in Uzbekistan.
The website serves as a professional online presence β replacing a traditional printed business card with a modern, animated, mobile-first web experience. Clients can instantly call Abdulaziz with one tap, view his services, read his background, and understand why to choose him β all from any device.
Who it is for:
- Clients who need reliable freight and parcel delivery
- Business owners looking for a professional courier partner
- Anyone searching for a trusted driver affiliated with Largo
What it replaces: A static paper business card β upgraded to a full-featured, SEO-optimized, always-online web presence.
| Feature | Description |
|---|---|
| π Dark / Light Mode | Persisted via localStorage, respects system prefers-color-scheme on first visit |
| π¬ Animated Loading Screen | Bouncing truck icon with a live progress bar (0 β 100%) before reveal |
| π Hero Section | Full-screen entry with floating stat cards, animated background blobs, profile photo, and CTA buttons |
| π€ About Section | Biography, personal info grid, and four animated statistics cards |
| π Services Section | 8 service cards in a responsive 4-column grid with staggered scroll-triggered entrance animations |
| β Why Choose Me Section | 6 quality cards with a gradient CTA banner |
| π Contact Section | Glassmorphism contact card with click-to-call integration |
| π’ Footer with Largo Logo | Drop-in logo slot β place /public/largo-logo.png and it renders automatically; graceful fallback placeholder if absent |
| π± Floating Phone Button | Appears after 400 px of scroll; expands to reveal clickable phone number with pulse animation |
| β¬οΈ Scroll To Top | Appears after 600 px; smooth scroll back to top |
| π§ Sticky Navbar | Active section detection via getBoundingClientRect; animated underline with Framer Motion layoutId; mobile hamburger menu with AnimatePresence |
| π Glassmorphism UI | .glass and .glass-card utility classes with backdrop-blur β fully adapted for both dark and light modes |
| π¨ Custom Color Palette | Brand colors primary (#2563EB) and accent (#22C55E) integrated into Tailwind's theme extension |
| π Framer Motion Animations | Scroll-triggered useInView, staggered children, hover lift effects, floating stat cards |
| πΌοΈ Optimized Images | next/image with AVIF + WebP auto-conversion, responsive sizes, fill prop, onError fallback |
| π€ Google Fonts β Inter | Loaded via next/font/google as a CSS variable; zero layout shift |
| π SEO Optimized | Uzbek <title>, <meta description>, keywords, OpenGraph tags, robots: index/follow |
| π± Fully Responsive | Mobile-first layout tested from 320 px to 1920 px |
| βΏ Accessibility | aria-label on all icon buttons, semantic HTML elements (<header>, <nav>, <main>, <footer>, <section>), keyboard-accessible navigation |
| π Static Generation | Entire site pre-rendered at build time β zero server cost, instant load |
| β‘ Performance | 61.3 kB page bundle, 164 kB First Load JS, passive scroll listeners, priority image preload on Hero |
| π― Phone Call Integration | tel: links throughout the site; primary CTA, navbar button, floating button, contact card, footer |
| ποΈ Custom CSS Animations | phone-pulse keyframe ring effect on call buttons; float animation on stat cards; pulse-slow |
| ποΈ Custom Scrollbar | Styled webkit scrollbar in both dark and light themes |
| Technology | Version | Role |
|---|---|---|
| Next.js | 15.5.19 | React framework β App Router, static generation, next/image, next/font |
| React | 18.3.1 | UI library |
| TypeScript | 5.8.3 | Static typing β strict mode, forceConsistentCasingInFileNames |
| Tailwind CSS | 3.4.17 | Utility-first styling, JIT, dark mode (class), custom color theme |
| Framer Motion | 11.18.2 | Animations β motion, AnimatePresence, useInView, layoutId |
| Lucide React | 0.400.0 | Icon library β 25 icons used across all components |
| clsx | 2.1.1 | Conditional class name construction |
| tailwind-merge | 2.6.0 | Merge Tailwind classes without conflicts (used in cn() helper) |
| PostCSS | 8.5.3 | CSS processing pipeline for Tailwind |
| Autoprefixer | 10.4.21 | Vendor prefixes for cross-browser CSS compatibility |
| ESLint | 8.57.1 | Linting with next/core-web-vitals ruleset |
abdulaziz-portfolio/
β
βββ public/ # Static assets served at root
β βββ abdulaziz.jpg # Profile photo (Hero section)
β βββ largo-logo.png # Largo company logo (Footer section)
β
βββ src/
β βββ app/ # Next.js App Router root
β β βββ globals.css # Global styles, Tailwind directives, custom utilities
β β βββ layout.tsx # Root layout β Inter font, SEO metadata, <html lang="uz">
β β βββ page.tsx # Page root β dark mode state, loading screen, section composition
β β
β βββ components/
β β βββ layout/
β β β βββ Navbar.tsx # Sticky navbar β active section detection, theme toggle, mobile menu
β β β
β β βββ sections/ # One file per page section
β β β βββ Hero.tsx # Full-screen hero β photo, badges, CTA, animated background
β β β βββ About.tsx # Biography, info grid, animated stat cards
β β β βββ Services.tsx # 8 service cards β 4-column responsive grid, stagger animation
β β β βββ WhyChooseMe.tsx # 6 quality cards + gradient CTA banner
β β β βββ Contact.tsx # Glassmorphism contact card with click-to-call
β β β βββ Footer.tsx # 3-column footer, Largo logo slot, copyright
β β β
β β βββ ui/ # Reusable floating UI components
β β βββ LoadingScreen.tsx # Animated intro screen with progress bar
β β βββ FloatingPhone.tsx # Scroll-triggered floating call button with tooltip
β β βββ ScrollToTop.tsx # Scroll-triggered back-to-top button
β β
β βββ lib/
β βββ utils.ts # cn() helper + phone number constants
β
βββ .eslintrc.json # ESLint config β next/core-web-vitals
βββ .gitignore # Standard Next.js gitignore
βββ .nvmrc # Pins Node.js 20 for local development
βββ .vercelignore # Excludes cache/node_modules from Vercel upload
βββ next.config.ts # Next.js config β reactStrictMode, image formats, lint/TS strict
βββ postcss.config.mjs # PostCSS β Tailwind + Autoprefixer
βββ tailwind.config.ts # Tailwind β darkMode, custom colors, safelist, animations
βββ tsconfig.json # TypeScript β strict, bundler resolution, path aliases
βββ vercel.json # Explicit Vercel deployment configuration
βββ package.json # Dependencies, scripts, Node.js engines constraint
Key directories:
src/app/β Next.js App Router entry points.layout.tsxhandles font loading and SEO.page.tsxorchestrates state and renders all sections in order.src/components/sections/β Each section is a self-contained'use client'component with its own animation variants and scroll-triggereduseInViewhook.src/components/ui/β Floating overlay components that mount globally and react to scroll position independently.src/lib/utils.tsβ Single source of truth for the phone number (change it once, updates everywhere).
- Node.js
>=18.17.0(Node 20 recommended β see.nvmrc) - npm
>=9
# 1. Clone the repository
git clone https://github.com/winter-eng/abdulaziz-portfolio.git
# 2. Navigate into the project
cd abdulaziz-portfolio
# 3. Install dependencies
npm install
# 4. Start the development server
npm run devOpen http://localhost:3000 in your browser.
# Create a production build
npm run build
# Start the production server locally
npm startThe build output is placed in .next/. The entire site is statically pre-rendered at build time.
Build output (reference):
Route (app) Size First Load JS
β β / 61.3 kB 164 kB
β β /_not-found 995 B 103 kB
β (Static) prerendered as static content
# Start development server with hot reload
npm run dev
# Type-check without emitting (catches all TS errors)
npm run type-check
# Lint all TypeScript/TSX files in src/ β fails on any warning
npm run lintWorkflow:
- Edit any file under
src/β the dev server hot-reloads instantly. - Run
npm run type-checkbefore committing to catch type errors early. - Run
npm run lintto ensure zero ESLint warnings. - Run
npm run buildto confirm production parity before pushing.
Path alias: @/ maps to src/ β use import Foo from '@/components/...' throughout.
This project ships with a vercel.json that explicitly configures the deployment.
# Option A β Vercel CLI
npm i -g vercel
vercel
# Option B β GitHub integration
# Push to GitHub β Import in vercel.com β Deploy automaticallyNo environment variables are required. Vercel detects Next.js via vercel.json and builds with npm run build.
vercel.json configuration:
{
"framework": "nextjs",
"buildCommand": "npm run build",
"installCommand": "npm install",
"outputDirectory": ".next"
}Deploy via drag-and-drop of the .next/ folder or connect the GitHub repository. Set:
- Build command:
npm run build - Publish directory:
.next - Node version:
20
- Node.js
>=18.17.0(specified inpackage.jsonenginesfield) - The
.nvmrcfile pins Node 20 fornvmusers
Drop your photo at:
public/abdulaziz.jpg
The image renders at 288Γ320 px on mobile and 384Γ480 px on desktop. A gradient fallback with a placeholder message displays automatically if the file is missing.
Drop the logo file at:
public/largo-logo.png
The Footer section renders it at 160Γ48 px with object-contain. A styled "LARGO" text placeholder is shown automatically when the file is absent β no code change required either way.
Edit a single file β src/lib/utils.ts:
export const PHONE_NUMBER = '+998997228280' // used in tel: href
export const PHONE_DISPLAY = '+998 99 722 82 80' // displayed to user
export const PHONE_HREF = `tel:${PHONE_NUMBER}`This constant is imported by Navbar, Hero, WhyChooseMe, Contact, Footer, and FloatingPhone β one change updates all.
| What to change | File | What to look for |
|---|---|---|
| Name, age, company, vehicle | src/components/sections/About.tsx |
The info grid array |
| Stats (500+, 200+, 3+, 100%) | src/components/sections/About.tsx |
const stats array |
| Hero tagline and subtitle | src/components/sections/Hero.tsx |
<motion.p> elements |
| Service cards | src/components/sections/Services.tsx |
const services array |
| Why Choose Me cards | src/components/sections/WhyChooseMe.tsx |
const qualities array |
| Contact details | src/components/sections/Contact.tsx |
const contactDetails array |
| SEO title and meta description | src/app/layout.tsx |
export const metadata |
| Footer copyright year | src/components/sections/Footer.tsx |
Β© 2026 |
Edit tailwind.config.ts:
theme: {
extend: {
colors: {
primary: {
DEFAULT: '#2563EB', // Change primary blue
600: '#2563EB',
},
accent: {
DEFAULT: '#22C55E', // Change accent green
},
},
},
},All icons come from Lucide React. Browse the library, then replace the named import in the relevant component. No extra packages needed.
Edit the navLinks array in both src/components/layout/Navbar.tsx and src/components/sections/Footer.tsx. Ensure the href value matches the id of the target <section>.
| Technique | Implementation |
|---|---|
| Static generation | All routes pre-rendered at build time (β in build output) β zero server-side rendering cost |
| Next.js Image optimization | next/image auto-converts to AVIF then WebP; serves correct size per viewport via sizes |
| Font optimization | Inter loaded via next/font/google β self-hosted, zero layout shift, CSS variable |
| Passive scroll listeners | All scroll event listeners use { passive: true } β never blocks the main thread |
| Priority image preload | Hero photo uses priority prop β preloaded in <head> for above-the-fold LCP |
| Lazy section animations | useInView with once: true β animations trigger once on entry, never re-run |
| Tree-shaken icons | Lucide React exports named icons β only the 25 used icons are bundled |
| Tailwind JIT | Only CSS classes present in source are included in the production bundle |
| Tailwind safelist | Dynamic class strings in JS object maps are explicitly safelisted β no purge risk in production |
| Breakpoint | Screen width | Layout behavior |
|---|---|---|
| Mobile | 320 px β 639 px | Single-column layouts; hamburger menu; stacked hero photo above text |
| Small | 640 px β 767 px | Wider spacing; horizontal CTA buttons; phone number visible in navbar |
| Medium | 768 px β 1023 px | Desktop nav visible; 2-column service grid |
| Large | 1024 px β 1279 px | 2-column hero layout (text left, photo right); 4-column service grid |
| XL+ | 1280 px + | Constrained to max-w-6xl container β no content stretching on ultra-wide screens |
All layouts are built mobile-first using Tailwind's sm:, md:, lg: responsive prefixes.
The following SEO features are implemented in src/app/layout.tsx via Next.js Metadata API:
<title>β Full descriptive title in Uzbek including name, role, and company<meta name="description">β Rich service description optimized for Uzbek search queries<meta name="keywords">β 9 targeted Uzbek-language keywords<meta name="author">βAbdusodiqov Abdulaziz- OpenGraph tags β
og:title,og:description,og:type: website,og:locale: uz_UZ robotsβindex: true,follow: truelang="uz"β<html>tag signals Uzbek language to search engines and assistive tech- Semantic HTML β
<header>,<nav>,<main>,<section id="...">,<footer>improve crawlability - Structured alt text β All images carry descriptive
altattributes
| Practice | Location |
|---|---|
aria-label on all icon-only buttons |
Navbar theme toggle, mobile menu button, FloatingPhone button, ScrollToTop button |
| Semantic landmarks | <header>, <nav>, <main>, <footer>, <section> β readable by screen readers |
lang="uz" on <html> |
Screen readers use correct Uzbek pronunciation |
suppressHydrationWarning on <html> |
Prevents hydration mismatch warning when dark mode class is toggled |
| Keyboard-accessible navigation | All interactive elements are <a>, <button>, or motion.button β focusable by default |
| Passive event listeners | Scroll handlers are non-blocking β no jank on assistive input devices |
| Script | Command | Description |
|---|---|---|
dev |
next dev |
Start local development server with hot reload at localhost:3000 |
build |
next build |
Create optimized production build in .next/ |
start |
next start |
Serve the production build locally |
lint |
eslint src --ext .ts,.tsx --max-warnings 0 |
Lint all TypeScript files; fails on any warning |
type-check |
tsc --noEmit |
Full TypeScript type check without emitting files |
| Package | Version | Purpose |
|---|---|---|
next |
15.5.19 | React framework β App Router, image optimization, font loading, static generation |
react |
^18.3.1 | UI library |
react-dom |
^18.3.1 | React DOM renderer |
framer-motion |
^11.18.2 | Production-grade animation library β scroll triggers, transitions, layout animations |
lucide-react |
^0.400.0 | Tree-shakeable SVG icon library |
clsx |
^2.1.1 | Tiny utility for building conditional className strings |
tailwind-merge |
^2.6.0 | Intelligently merges Tailwind classes, resolving conflicts |
| Package | Version | Purpose |
|---|---|---|
typescript |
^5.8.3 | TypeScript compiler |
@types/node |
^20.17.0 | Node.js type definitions |
@types/react |
^18.3.20 | React type definitions |
@types/react-dom |
^18.3.5 | React DOM type definitions |
tailwindcss |
^3.4.17 | Tailwind CSS framework |
postcss |
^8.5.3 | CSS transformation pipeline |
autoprefixer |
^10.4.21 | Adds vendor prefixes to CSS automatically |
eslint |
^8.57.1 | JavaScript/TypeScript linter |
eslint-config-next |
15.5.19 | Next.js ESLint rules (Core Web Vitals + accessibility) |
| Browser | Support | Notes |
|---|---|---|
| Chrome | β 90+ | Full support including backdrop-filter for glassmorphism |
| Firefox | β 103+ | Full support; backdrop-filter enabled by default since Firefox 103 |
| Safari | β 14+ | Full support; -webkit-backdrop-filter applied via Autoprefixer |
| Edge | β 90+ | Chromium-based; same as Chrome |
| Mobile Safari | β iOS 14+ | backdrop-filter supported |
| Chrome Android | β 90+ | Full support |
| IE 11 | β | Not supported β targets ES2017+ and modern CSS |
Contributions, suggestions, and bug reports are welcome.
- Fork the repository
- Create a feature branch β
git checkout -b feat/your-feature - Commit your changes β
git commit -m "feat: add your feature" - Push to your branch β
git push origin feat/your-feature - Open a Pull Request
Before submitting, ensure all checks pass:
npm run type-check # Zero TypeScript errors
npm run lint # Zero ESLint warnings
npm run build # Clean production buildThis project is licensed under the MIT License.
MIT License
Copyright (c) 2026 winter-eng
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Developer: Winter
This project is built on the shoulders of exceptional open-source technology:
- Next.js by Vercel β the most capable React framework for production
- Framer Motion β the gold standard for React animations
- Tailwind CSS β utility-first CSS that scales
- Lucide β beautifully consistent open-source icons
- Inter by Rasmus Andersson β the typeface designed for screens
- Vercel β zero-configuration deployment for Next.js
Built with β€οΈ for Abdusodiqov Abdulaziz Β· Professional Delivery Driver Β· Largo
Fast. Reliable. On time.