# Membuat Website Portofolio dengan Django
## Prepare Django Project
##### 1. Buat direktori kerja baru dan masuk kedalam direktori kerjanya di visual studio code

##### 2. Buat virtual environment dan aktifkan di terminal cmd
```markdown!
python -m venv env
.\env\Scripts\activate
#output
(env) C:\Dev\project-akhir>
```
##### 3. check pip version
```markdown!
python -m pip --version
#upgrade pip
python -m pip install --upgrade pip
```
##### 4. install django
```markdown!
py -m pip install Django
```
##### 5. install dependency
```markdown!
pip install psycopg2
pip install gunicorn dj-database-url
pip install django-crispy-forms
pip install pillow
```
##### 6. Menyimpan dependency yang sudah terinstall
```markdown!
pip freeze > requirements.txt
```
## Membuat Web Portofolio
##### 1. buat proyek baru
```markdown!
django-admin startproject portofolioku
cd portofolioku
```
##### 2. migrate database
```markdown!
python manage.py migrate
```
##### 3. runserver
```markdown!
python manage.py runserver
```
##### 4. Buat aplikasi
```markdown!
django-admin startapp base
```
##### 5. tambahkan apps yang telah dibuat di file settings.py
```markdown!
INSTALLED_APPS = [
.
.
.
'base',
]
```
##### 7. buat direktori `templates` didalam direktori `base`

##### 8. buat `index.html` didalam direktori templates
```markdown!
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="{% static 'css/styles.css' %}" />
<link rel="stylesheet" href="{% static 'css/responsive.css' %}" />
<title>Satria Galih Setia Yudha - Telecommunication Engineer</title>
<link rel="icon" href="{% static 'favian.ico' %}" type="image/x-icon">
<!-- Google Font -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
<!-- Tambahan CSS untuk beautify -->
<style>
body {
font-family: 'Poppins', sans-serif;
background: #f9f9f9;
color: #333;
}
section {
padding: 80px 20px;
}
h2.section-title {
text-align: center;
font-size: 2.5rem;
margin-bottom: 40px;
color: #333;
}
.card {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12);
}
.portfolio .card,
.experience-item,
.education-item,
.contact-item {
margin-bottom: 30px;
}
.back-to-top {
position: fixed;
bottom: 30px;
right: 30px;
font-size: 1.5rem;
background: #007bff;
color: white;
border: none;
border-radius: 50%;
width: 45px;
height: 45px;
cursor: pointer;
box-shadow: 0 6px 16px rgba(0, 123, 255, 0.4);
z-index: 999;
display: none;
transition: background 0.3s ease;
}
.back-to-top:hover {
background: #0056b3;
}
nav ul li a.active {
font-weight: bold;
color: #007bff !important;
}
/* Animasi saat scroll */
[data-animate] {
opacity: 0;
transform: translateY(30px);
transition: all 0.6s ease-out;
}
</style>
</head>
<body>
<!-- Header -->
<header>
<div class="main-container">
<div class="nav">
<div class="logo">
<a href="/">Portofolio</a>
</div>
<nav>
<ul>
<li><a href="#services">Expertise</a></li>
<li><a href="#experience">Experience</a></li>
<li><a href="#portfolios">Projects</a></li>
<li><a href="#education">Education</a></li>
<li><a href="#skills">Skill</a></li>
<li><a href="#contact">Contact</a></li>
<li>
<a href="{% static 'resume.pdf' %}" target="_blank" class="btn">Resume</a>
</li>
</ul>
</nav>
<div class="burger">
<div class="line-1"></div>
<div class="line-2"></div>
<div class="line-3"></div>
</div>
</div>
<section id="hero">
<div class="hero-container main-container"> <!-- Tambahkan wrapper container -->
<div class="hero-grid"> <!-- Tambahkan div untuk konten teks -->
<div class="hero-left">
<h3 class="pre-title">Telecommunication Engineer</h3>
<h1 class="hero-name">Satria Galih Setia <span>Yudha</span></h1>
<p class="hero-description">
Specializing in network infrastructure, Linux administration, and MikroTik solutions.
With hands-on experience at Telkom Indonesia and multiple certifications including
MTCNA and CCNA, I deliver efficient and secure network solutions.
</p>
<div class="social-links">
<a href="https://www.linkedin.com/in/satriagalihsetiayudha/" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>
</svg>
</a>
<a href="https://www.instagram.com/sattrrrr__/" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/>
</svg>
</a>
</div>
</div>
<div class="hero-right">
<div class="hero-image-container">
<img src="{% static 'images/hero.png' %}" alt="Satria Galih Setia Yudha" class="hero-image"/>
</div>
</div>
</div>
</div>
</section>
<!-- End Header -->
<!-- Services -->
<section id="services">
<div class="main-container">
<div class="services main-container">
<h3 class="pre-title">What I Do</h3>
<h1 class="section-title services-title">My Expertise</h1>
<div class="grid-3">
<div class="service">
<div class="service-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1 17l-5-5.299 1.399-1.43 3.574 3.736 6.572-7.007 1.455 1.403-8 8.597z"/>
</svg>
</div>
<h4>Network Infrastructure</h4>
<p>
Design, implement, and maintain robust network infrastructures with expertise in
MikroTik, Cisco, and wireless networking solutions.
</p>
</div>
<div class="service">
<div class="service-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M12 0l-11 6v12.131l11 5.869 11-5.869v-12.066l-11-6.065zm-9 8.23l8 4.363v8.607l-8-4.268v-8.702zm10 12.97v-8.6l8-4.269v8.6l-8 4.269z"/>
</svg>
</div>
<h4>Linux Administration</h4>
<p>
Proficient in Linux server management, containerization with Docker, and deploying
enterprise applications in Linux environments.
</p>
</div>
<div class="service">
<div class="service-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm6 13h-5v5h-2v-5h-5v-2h5v-5h2v5h5v2z"/>
</svg>
</div>
<h4>Cloud Network Optimization</h4>
<p>
Build and optimize secure, scalable cloud networks for peak performance, leveraging hybrid and multi-cloud strategies to meet evolving business demands.
</p>
</div>
</div>
</div>
</div>
</section>
<!-- End Services -->
<!-- Experience Section -->
<section id="experience">
<div class="main-container">
<div class="experience main-container">
<h3 class="pre-title">Career Journey</h3>
<h1 class="section-title">Professional Experience</h1>
<div class="experience-container">
<!-- Experience 1 -->
<div class="experience-item card">
<div class="experience-header">
<div class="experience-title">
<h3>Student Internship</h3>
<h4>Mobility & FMC Lab. DCS Telkom · PT. Telkom Indonesia</h4>
</div>
<div class="experience-date">
<span>Apr 2023 - Sep 2023</span>
<span>6 months</span>
</div>
</div>
<div class="experience-details">
<ul>
<li>Assisted in managing and troubleshooting hardware, software, and computer network issues</li>
<li>Performed hardware upgrades including servers and PCs</li>
<li>Conducted research on network devices such as routers and access points</li>
</ul>
<div class="experience-skills">
<span>Wireless Technologies</span>
<span>Wireless Networking</span>
<span>Network Administration</span>
<span>Hardware Maintenance</span>
</div>
<a href="{% static 'Sign_Sertifikat Satria Galih.pdf' %}" target="_blank" class="experience-certificate">
View Certificate
</a>
</div>
</div>
<!-- You can add more experience items here -->
</div>
</div>
</div>
</section>
<!-- Portfolios -->
<section id="portfolios">
<div class="main-container">
<div class="portfolios main-container">
<h3 class="pre-title">My Works</h3>
<h1 class="section-title">Featured Projects</h1>
<div class="grid-3">
<!-- Portfolio 1 -->
<div class="portfolio">
<div class="portfolio-cover">
<img
src="{% static 'images/portfolio-1.jpeg' %}"
alt="Inventory Management System"
/>
</div>
<div class="portfolio-info">
<div class="portfolio-title">
<h4>Inventory Management System</h4>
</div>
<div class="portfolio-tags">
<div>Docker</div>
<div>Odoo</div>
<div>Linux</div>
</div>
<p>
Developed a comprehensive inventory management and POS system using Odoo in Docker
containers, ensuring scalability and easy deployment.
</p>
</div>
</div>
<!-- Portfolio 2 -->
<div class="portfolio">
<div class="portfolio-cover">
<img
src="{% static 'images/portfolio-2.jpeg' %}"
alt="AApanel Network Configuration"
/>
</div>
<div class="portfolio-info">
<div class="portfolio-title">
<h4>AApanel Network Setup</h4>
<a href="#" class="portfolio-link">
</a>
</div>
<div class="portfolio-tags">
<div>Linux</div>
<div>Networking</div>
<div>AApanel</div>
</div>
<p>
Installed and configured AApanel on a network infrastructure, optimizing server
performance and implementing security measures.
</p>
</div>
</div>
<!-- Portfolio 3 -->
<div class="portfolio">
<div class="portfolio-cover">
<img
src="{% static 'images/portfolio-3.jpeg' %}"
alt="Netwatch Failover Configuration on MikroTik"
/>
</div>
<div class="portfolio-info">
<div class="portfolio-title">
<h4>Captive Portal Solution</h4>
<a href="#" class="portfolio-link">
</a>
</div>
<div class="portfolio-tags">
<div>MikroTik</div>
<div>Wireless</div>
<div>Iron Wifi</div>
</div>
<p>
Failover ensures uninterrupted internet by automatically switching to a backup connection if the primary one fails.
MikroTik's Netwatch monitors the connection status at set intervals to trigger this switch.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- End Portfolios -->
<!-- Education Section -->
<section id="education">
<div class="main-container">
<div class="education-section main-container">
<h3 class="pre-title">Learning Path</h3>
<h1 class="section-title">Education</h1>
<div class="education-container">
<div class="education-item card">
<div class="line">
<div></div>
</div>
<div class="education-info">
<h4 class="education-title">Telkom University</h4>
<p>Bachelor Degree - Telecommunication Engineering</p>
<div class="education-meta">
<span class="education-years">2024 - Present</span>
<span class="education-gpa">GPA: 3.61</span>
</div>
</div>
</div>
<div class="education-item card">
<div class="line">
<div></div>
</div>
<div class="education-info">
<h4 class="education-title">SMK Telkom Purwokerto</h4>
<p>Computer and Network Engineering</p>
<div class="education-meta">
<span class="education-years">2021 - 2024</span>
<span class="education-gpa">GPA: 91.66</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Skills Section -->
<section id="skills">
<div class="main-container">
<div class="skills main-container">
<h3 class="pre-title">Technical Expertise</h3>
<h1 class="section-title">Skills & Competencies</h1>
<div class="skills-grid">
<div class="skills-right">
<p>
With 3+ years of hands-on experience in Network Engineering and Linux Administration,
I specialize in deploying secure and efficient network solutions. My technical expertise includes:
</p>
<div class="skills-list">
<ul>
<li>MikroTik (MTCNA Certified)</li>
<li>Cisco Networking (CCNA)</li>
<li>Linux Server Administration</li>
<li>Docker & Containerization</li>
</ul>
<ul>
<li>Wireless Networking</li>
<li>Virtualization (VirtualBox)</li>
<li>Network Troubleshooting</li>
<li>Hardware Installation</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Contact -->
<!-- <section id="contact">
<div class="main-container">
<div class="contact main-container">
<div class="contact-left">
<form
action="https://formspree.io/f/xeqwdykj"
method="POST"
class="contact-form"
>
<div>
<input type="text" placeholder="Name" name="name" required />
</div>
<div>
<input type="email" placeholder="Email" name="email" required />
</div>
<div>
<textarea
name="message"
id="message"
cols="30"
rows="10"
placeholder="Message"
required
></textarea>
</div>
<div>
<button class="btn-submit">Send Message</button>
</div>
</form>
</div> -->
<section id="contact">
<div class="contact-right">
<div class="main-container">
<div class="contact-item">
<div class="contact-item-icon">
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
viewBox="0 0 24 24"
>
<path
d="M12 1c-3.148 0-6 2.553-6 5.702 0 3.148 2.602 6.907 6 12.298 3.398-5.391 6-9.15 6-12.298 0-3.149-2.851-5.702-6-5.702zm0 8c-1.105 0-2-.895-2-2s.895-2 2-2 2 .895 2 2-.895 2-2 2zm12 14h-24l4-8h3.135c.385.641.798 1.309 1.232 2h-3.131l-2 4h17.527l-2-4h-3.131c.435-.691.848-1.359 1.232-2h3.136l4 8z"
/>
</svg>
</div>
<div class="contact-item-detail">
<h4>Location</h4>
<p>Purbalingga, Jawa Tengah, Indonesia</p>
</div>
</div>
<div class="contact-item">
<div class="contact-item-icon">
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
viewBox="0 0 24 24"
>
<path
d="M20 22.621l-3.521-6.795c-.008.004-1.974.97-2.064 1.011-2.24 1.086-6.799-7.82-4.609-8.994l2.083-1.026-3.493-6.817-2.106 1.039c-7.202 3.755 4.233 25.982 11.6 22.615.121-.055 2.102-1.029 2.11-1.033z"
/>
</svg>
</div>
<div class="contact-item-detail">
<h4>Phone</h4>
<p>+62 889 0597 4081</p>
</div>
</div>
<div class="contact-item">
<div class="contact-item-icon">
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
viewBox="0 0 24 24"
>
<path
d="M0 3v18h24v-18h-24zm21.518 2l-9.518 7.713-9.518-7.713h19.036zm-19.518 14v-11.817l10 8.104 10-8.104v11.817h-20z"
/>
</svg>
</div>
<div class="contact-item-detail">
<h4>Email</h4>
<p>iaayudha@gmail.com</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- End Contact -->
<!-- Footer -->
<footer>
<div class="footer-icons">
<a href="https://www.linkedin.com/in/satriagalihsetiayudha/" target="_blank">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>
</svg>
</a>
<a href="https://www.instagram.com/sattrrrr__/" target="_blank">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/>
</svg>
</a>
<a href="mailto:iaayudha@gmail.com">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M0 3v18h24v-18h-24zm21.518 2l-9.518 7.713-9.518-7.713h19.036zm-19.518 14v-11.817l10 8.104 10-8.104v11.817h-20z"/>
</svg>
</a>
<a href="tel:+6288905974081">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M20 22.621l-3.521-6.795c-.008.004-1.974.97-2.064 1.011-2.24 1.086-6.799-7.82-4.609-8.994l2.083-1.026-3.493-6.817-2.106 1.039c-7.202 3.755 4.233 25.982 11.6 22.615.121-.055 2.102-1.029 2.11-1.033z"/>
</svg>
</a>
</div>
<p>© 2025 Satria Galih Setia Yudha. All rights reserved.</p>
</footer>
<!-- End Footer -->
<script src="{% static 'js/main.js' %}"></script>
</body>
</html>
```
##### 9. buat folder static di dalam direktori portofolio

##### 10. buat folder images, js, dan css didalam diretori static

##### 11. buat file `styles.css` dan `responsive.css` di dalam direktori css
responsive.css
```markdown!
@media screen and (max-width: 1200px) {
.main-container {
width: 100%;
padding: 0 15px;
}
.nav {
padding: 1rem 15px;
}
#hero {
padding: 4rem 15px;
}
section {
padding-left: 15px;
padding-right: 15px;
}
}
@media screen and (max-width: 1000px) {
:root {
--sectionPadding: 5rem 0;
}
p {
font-size: 0.95rem;
line-height: 1.7;
}
.hero-name {
font-size: 3rem;
}
.grid-3 {
gap: 2rem;
}
.skills-list {
grid-template-columns: 1fr;
}
.contact {
gap: 2rem;
}
}
@media screen and (max-width: 825px) {
/* Burger Menu */
.burger {
display: block;
cursor: pointer;
}
.toggle-burger .line-1 {
transform: rotate(-45deg) translate(-5px, 7px);
}
.toggle-burger .line-2 {
opacity: 0;
}
.toggle-burger .line-3 {
transform: rotate(45deg) translate(-5px, -7px);
}
/* Navigation */
nav {
position: static;
width: 60%;
right: 0;
top: 0;
height: 100vh;
flex-direction: column;
background: var(--primaryBackgroundColor);
border-left: 1px solid var(--borderColor);
z-index: 9;
transform: translateX(100%);
transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
padding: 1rem 0;
box-shadow: -10px 0 30px rgba(0, 0, 0, 0.1);
}
nav ul {
flex-direction: column;
gap: 2.5rem;
}
.nav-active {
transform: translateX(0);
}
:root {
--sectionPadding: 4rem 0;
}
/* Titles */
.section-title {
font-size: 2rem;
margin: 0.6rem 0 3rem;
}
.pre-title {
font-size: 0.85rem;
}
/* Hero Section */
#hero {
grid-template-columns: 1fr;
height: auto;
padding: 3rem 0;
}
.hero-right {
order: -1;
margin-bottom: 3rem;
}
.hero-right img {
width: 80%;
max-width: 400px;
}
.hero-left {
text-align: center;
}
.hero-name {
font-size: 2.5rem;
}
.social-links {
justify-content: center;
}
/* Skills Section */
.skills-grid {
gap: 2rem;
}
.education {
margin-bottom: 2rem;
}
/* Footer */
footer {
padding: 3rem 0;
}
}
@media screen and (max-width: 640px) {
/* Titles */
.section-title {
font-size: 1.8rem;
margin-bottom: 2.5rem;
}
.pre-title {
font-size: 0.8rem;
letter-spacing: 0.2rem;
}
/* Hero */
.hero-name {
font-size: 2.2rem;
}
/* Services */
.service {
padding: 2rem 1.5rem;
}
/* Portfolio */
.portfolio-cover {
height: 200px;
}
/* Contact */
.contact-item {
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
.contact-item-icon {
width: 50px;
height: 50px;
}
/* Footer */
.footer-icons {
gap: 1rem;
}
}
@media screen and (max-width: 480px) {
:root {
--sectionPadding: 3.5rem 0;
}
/* Navigation */
nav {
width: 80%;
}
/* Hero */
.hero-name {
font-size: 2rem;
}
@media screen and (max-width: 768px) {
.hero-image-container {
width: 280px;
height: 280px;
margin: 0 auto;
}
@media screen and (max-width: 480px) {
.hero-image-container {
width: 220px;
height: 220px;
}
}
}
/* Portfolio */
.grid-3 {
grid-template-columns: 1fr;
}
/* Skills */
.skills-grid {
grid-template-columns: 1fr;
}
/* Contact Form */
.contact-form input,
.contact-form textarea {
padding: 0.8rem 1.2rem;
}
/* Footer */
footer p {
font-size: 0.9rem;
}
}
/* Special height adjustments for mobile */
@media screen and (max-height: 700px) and (orientation: landscape) {
#hero {
height: auto;
padding: 4rem 0;
}
.hero-right img {
width: 50%;
}
nav ul {
gap: 1.5rem;
}
}
@media screen and (max-width: 768px) {
.experience-header {
flex-direction: column;
}
.experience-date {
text-align: left;
}
.experience-skills span {
font-size: 0.8rem;
}
}
@media screen and (max-width: 480px) {
.experience-item {
padding: 1.5rem;
}
.education-item {
margin-bottom: 2rem;
}
}
/* Dark mode preference */
/*
@media (prefers-color-scheme: dark) {
:root {
--primaryTextColor: #f7fafc;
--secondaryTextColor: #e2e8f0;
--borderColor: #2d3748;
--lineColor: #4a5568;
--primaryBackgroundColor: #1a202c;
--secondaryBackgroundColor: #2d3748;
--thirdBackgroundColor: #4a5568;
}
.service, .portfolio {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2), 0 2px 4px -1px rgba(0, 0, 0, 0.1);
}
}
*/
```
styles.css
```markdown!
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap");
:root {
--primaryTextColor: #1F2937;
--secondaryTextColor: #4B5563;
--accentColor: #3B82F6;
--accentHover: #2563EB;
--borderColor: #E5E7EB;
--lineColor: #D1D5DB;
--primaryBackgroundColor: #FFFFFF;
--secondaryBackgroundColor: #F9FAFB;
--thirdBackgroundColor: #EFF6FF;
--sectionPadding: 6rem 0;
--itemBorderRadius: 0.75rem;
--boxShadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
scroll-behavior: smooth;
}
body {
font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.7;
color: var(--secondaryTextColor);
background-color: var(--primaryBackgroundColor);
}
h1, h2, h3, h4, h5, h6, strong {
color: var(--primaryTextColor);
font-weight: 700;
letter-spacing: -0.025em;
}
p {
font-size: 1.05rem;
line-height: 1.8rem;
color: var(--secondaryTextColor);
}
a {
text-decoration: none;
color: inherit;
transition: all 0.3s ease;
}
.main-container {
width: 100%;
max-width: none;
margin: 0;
padding: 0 20px;
}
@media screen and (max-width: 1200px) {
.main-container {
width: 90%;
}
}
.btn {
padding: 0.8rem 1.5rem;
background: var(--accentColor);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
color: white;
border: none;
border-radius: var(--itemBorderRadius);
cursor: pointer;
transition: all 0.3s ease;
font-weight: 500;
display: inline-block;
position: relative;
overflow: hidden;
z-index: 1;
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: 0.5s;
z-index: -1;
}
.btn:hover {
background: var(--accentHover);
transform: translateY(-2px);
box-shadow: var(--boxShadow);
}
.btn:hover::before {
left: 100%;
}
.section-title {
margin: 1rem 0 4rem;
font-size: 2.25rem;
text-align: center;
position: relative;
display: inline-block;
font-weight: 800;
letter-spacing: -0.03em;
}
.section-title::after {
content: '';
position: absolute;
width: 50%;
height: 4px;
background: linear-gradient(to right, var(--accentColor), transparent);
bottom: -10px;
left: 25%;
border-radius: 2px;
}
.pre-title {
text-transform: uppercase;
letter-spacing: 0.3rem;
color: var(--secondaryTextColor);
position: relative;
padding-left: 40px;
width: fit-content;
font-weight: 400;
font-size: 0.9rem;
display: block;
margin: 0 auto 1rem;
}
.pre-title::before {
content: "";
width: 30px;
height: 1px;
background: var(--lineColor);
position: absolute;
display: block;
left: 0;
top: 50%;
}
.grid-3 {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 3rem;
}
.nav {
display: flex;
justify-content: space-between;
padding: 1rem 20px;
align-items: center;
position: sticky;
top: 0;
background-color: var(--primaryBackgroundColor);
z-index: 1000;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
nav ul {
list-style: none;
display: flex;
gap: 2.5rem;
}
.logo {
display: flex;
align-items: center;
font-weight: 700;
font-size: 1.8rem;
color: var(--accentColor);
}
nav ul li {
display: flex;
align-items: center;
}
nav ul li a {
font-weight: 500;
position: relative;
}
nav ul li a::after {
content: '';
position: absolute;
width: 0;
height: 2px;
bottom: -4px;
left: 0;
background-color: var(--accentColor);
transition: width 0.3s ease;
}
nav ul li a:hover::after {
width: 100%;
}
.burger div {
width: 25px;
height: 2px;
background-color: var(--primaryTextColor);
margin: 7px;
transition: all 0.3s;
z-index: 99;
}
.burger {
display: none;
z-index: 1001;
position: fixed;
top: 33px;
right: 35px;
}
#hero {
padding: var(--sectionPadding);
background: linear-gradient(135deg, #f8fafc 0%, #f0f9ff 100%);
width: 100vw;
margin-left: calc(-50vw + 50%);
}
.hero-description {
text-align: justify;
text-justify: inter-word;
}
.hero-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 3rem;
align-items: center;
}
.hero-left {
padding: 2rem;
border-radius: var(--itemBorderRadius);
background: linear-gradient(135deg, rgba(249, 250, 251, 0.9) 0%, rgba(239, 246, 255, 0.9) 100%);
backdrop-filter: blur(5px);
}
.hero-name {
font-size: 3.5rem;
font-weight: 700;
line-height: 1.1;
margin: 0.5rem 0 1.5rem;
background: linear-gradient(to right, var(--primaryTextColor) 60%, var(--accentColor));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.hero-name span {
color: var(--accentColor) !important;
}
.hero-right img {
width: 100%;
max-width: 500px;
border-radius: var(--itemBorderRadius);
box-shadow: var(--boxShadow);
transition: transform 0.3s ease;
}
.hero-right img:hover {
transform: scale(1.02);
}
.hero-right {
display: flex;
justify-content: center;
}
.hero-image-container {
width: 320px;
height: 320px;
border-radius: 50%;
overflow: hidden;
border: 3px solid var(--accentColor);
box-shadow: 0 10px 30px rgba(79, 70, 229, 0.2);
position: relative;
animation: float 6s ease-in-out infinite;
}
.hero-image {
border-radius: 8px;
border: 3px solid var(--accentColor);
transform: rotate(3deg);
transition: transform 0.3s ease;
}
.hero-image:hover {
transform: rotate(0);
}
.hero-container {
padding: 0 clamp(20px, 5vw, 60px);
}
.social-links {
display: flex;
gap: 1.5rem;
margin-top: 2rem;
}
.social-links a {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--thirdBackgroundColor);
transition: all 0.3s ease;
}
.social-links a:hover {
background: var(--accentColor);
transform: translateY(-3px);
}
.social-links a:hover svg {
fill: white;
}
.social-links svg {
width: 20px;
height: 20px;
fill: var(--primaryTextColor);
}
#services {
background-color: var(--secondaryBackgroundColor);
padding: var(--sectionPadding);
position: relative;
overflow: hidden;
}
#services::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: radial-gradient(circle at 10% 20%, rgba(59, 130, 246, 0.03) 0%, transparent 20%);
pointer-events: none;
}
.service {
padding: 2.5rem;
text-align: center;
border-radius: 16px;
background: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
position: relative;
overflow: hidden;
animation: fadeIn 0.6s ease forwards;
}
.service::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 4px;
background: var(--accentColor);
transform: scaleX(0);
transform-origin: left;
transition: transform 0.3s ease;
}
.service:hover {
transform: translateY(-10px) scale(1.02);
box-shadow: 0 15px 30px rgba(59, 130, 246, 0.15);
}
.service:hover::after {
transform: scaleX(1);
}
.service h4 {
margin: 1.5rem 0;
font-weight: 600;
font-size: 1.2rem;
}
.service-icon {
background: var(--thirdBackgroundColor);
width: fit-content;
margin: 0 auto;
padding: 1.2rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.service-icon svg {
fill: var(--accentColor);
width: 30px;
height: 30px;
}
#experience {
padding: var(--sectionPadding);
background-color: var(--secondaryBackgroundColor);
position: relative;
overflow: hidden;
}
#experience::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: radial-gradient(circle at 10% 20%, rgba(59, 130, 246, 0.03) 0%, transparent 20%);
pointer-events: none;
}
.experience-container {
display: flex;
flex-direction: column;
gap: 2.5rem;
}
.experience-item {
background: var(--primaryBackgroundColor);
border-radius: var(--itemBorderRadius);
padding: 2rem;
box-shadow: var(--boxShadow);
transition: transform 0.3s ease;
animation: fadeIn 0.6s ease forwards;
}
.experience-item:hover {
transform: translateY(-5px);
}
.experience-header {
display: flex;
justify-content: space-between;
margin-bottom: 1.5rem;
flex-wrap: wrap;
gap: 1rem;
}
.experience-title h3 {
color: var(--accentColor);
font-size: 1.3rem;
margin-bottom: 0.5rem;
}
.experience-title h4 {
font-weight: 500;
color: var(--secondaryTextColor);
}
.experience-date {
text-align: right;
}
.experience-date span {
display: block;
color: var(--secondaryTextColor);
}
.experience-date span:first-child {
font-weight: 500;
color: var(--primaryTextColor);
}
.experience-details ul {
margin: 1rem 0;
padding-left: 1.5rem;
}
.experience-details li {
margin-bottom: 0.8rem;
position: relative;
list-style-type: none;
}
.experience-details li::before {
content: "▹";
position: absolute;
left: -1.5rem;
color: var(--accentColor);
}
.experience-skills {
display: flex;
flex-wrap: wrap;
gap: 0.8rem;
margin: 1.5rem 0;
}
.experience-skills span {
background: var(--thirdBackgroundColor);
padding: 0.4rem 0.8rem;
border-radius: 50px;
font-size: 0.85rem;
}
.experience-certificate {
display: inline-block;
color: var(--accentColor);
font-weight: 500;
margin-top: 1rem;
transition: all 0.3s ease;
}
.experience-certificate:hover {
color: var(--accentHover);
transform: translateX(5px);
}
#portfolios {
padding: var(--sectionPadding);
}
.portfolio {
border-radius: 16px;
overflow: hidden;
border: 1px solid var(--borderColor);
transition: all 0.4s ease;
background: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
position: relative;
animation: fadeIn 0.6s ease forwards;
}
.portfolio::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(to bottom, transparent 60%, rgba(0, 0, 0, 0.7));
opacity: 0;
transition: opacity 0.3s ease;
z-index: 1;
}
.portfolio:hover {
transform: translateY(-8px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.portfolio:hover::before {
opacity: 1;
}
.portfolio-cover {
height: 250px;
overflow: hidden;
}
.portfolio img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.portfolio:hover img {
transform: scale(1.05);
}
.portfolio-info {
padding: 2rem 1.5rem;
position: relative;
z-index: 2;
transition: transform 0.3s ease;
}
.portfolio:hover .portfolio-info {
transform: translateY(-10px);
}
.portfolio-title {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
}
.portfolio h4 {
font-weight: 600;
font-size: 1.2rem;
}
.portfolio-title a svg {
fill: var(--secondaryTextColor);
transition: all 0.3s ease;
}
.portfolio-title a:hover svg {
fill: var(--accentColor);
transform: translateX(3px);
}
.portfolio-tags {
display: flex;
gap: 0.8rem;
margin: 1rem 0;
flex-wrap: wrap;
}
.portfolio-tags div {
font-size: 0.8rem;
border: 1px solid var(--borderColor);
padding: 0.4rem 0.8rem;
color: var(--secondaryTextColor);
border-radius: 50px;
background: var(--secondaryBackgroundColor);
}
#skills {
padding: var(--sectionPadding);
background: var(--secondaryBackgroundColor);
position: relative;
overflow: hidden;
}
#skills::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: radial-gradient(circle at 10% 20%, rgba(59, 130, 246, 0.03) 0%, transparent 20%);
pointer-events: none;
}
.skills-grid {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
}
.skills-right {
max-width: 800px;
margin: 0 auto;
}
.skills-list {
display: grid;
grid-template-columns: 1fr 1fr;
margin-top: 2rem;
gap: 1.5rem;
}
.skills-list ul {
list-style: none;
}
.skills-list li {
margin-bottom: 1rem;
position: relative;
padding-left: 1.5rem;
}
.skills-list li::before {
content: "▹";
position: absolute;
left: 0;
color: var(--accentColor);
}
.education {
display: flex;
gap: 1.5rem;
margin-bottom: 3rem;
animation: fadeIn 0.6s ease forwards;
}
.education .line {
padding: 0 0.7rem;
}
.education .line div {
width: 2px;
height: 100%;
background: var(--borderColor);
position: relative;
}
.education-info p {
margin: 0.6rem 0 1.4rem;
color: var(--secondaryTextColor);
}
.education-years {
margin-bottom: 1rem;
color: var(--accentColor);
font-weight: 500;
}
.education .line div:before {
content: "";
width: 15px;
height: 15px;
background: var(--accentColor);
border-radius: 50%;
position: absolute;
left: -6px;
top: 0;
}
#contact {
padding: var(--sectionPadding);
background: var(--primaryBackgroundColor);
}
.contact {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 4rem;
}
.contact-form div {
margin-bottom: 1.5rem;
}
.contact-form input,
.contact-form textarea {
width: 100%;
padding: 1rem 1.5rem;
font-family: "Poppins", sans-serif;
background: var(--secondaryBackgroundColor);
border: 1px solid var(--borderColor);
border-radius: var(--itemBorderRadius);
resize: none;
transition: all 0.3s ease;
}
.contact-form input:focus,
.contact-form textarea:focus {
outline: none;
border-color: var(--accentColor);
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}
.btn-submit {
width: 100%;
padding: 1rem;
background-color: var(--accentColor);
color: #fff;
border: none;
border-radius: var(--itemBorderRadius);
cursor: pointer;
transition: all 0.3s ease;
font-weight: 500;
font-size: 1rem;
}
.btn-submit:hover {
background-color: var(--accentHover);
transform: translateY(-2px);
box-shadow: var(--boxShadow);
}
.contact-item {
display: flex;
gap: 1.5rem;
margin-bottom: 2.5rem;
align-items: flex-start;
animation: fadeIn 0.6s ease forwards;
}
.contact-item-icon {
background: var(--thirdBackgroundColor);
width: 60px;
height: 60px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all 0.3s ease;
}
.contact-item:hover .contact-item-icon {
background: var(--accentColor);
transform: rotate(5deg);
}
.contact-item:hover svg {
fill: white;
}
.contact-item-icon svg {
fill: var(--accentColor);
width: 24px;
height: 24px;
transition: all 0.3s ease;
}
.contact-item-detail h4 {
margin-bottom: 0.6rem;
font-size: 1.1rem;
}
footer {
padding: 4rem 0;
background: var(--secondaryBackgroundColor);
text-align: center;
}
.footer-icons {
margin-bottom: 2rem;
display: flex;
justify-content: center;
gap: 1.5rem;
}
.footer-icons a {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--thirdBackgroundColor);
transition: all 0.3s ease;
}
.footer-icons a:hover {
background: var(--accentColor);
transform: translateY(-3px);
}
.footer-icons a:hover svg {
fill: white;
}
.footer-icons svg {
width: 20px;
height: 20px;
fill: var(--primaryTextColor);
transition: all 0.3s ease;
}
/* Animations */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Back to top button */
.back-to-top {
position: fixed;
bottom: 2rem;
right: 2rem;
width: 50px;
height: 50px;
border-radius: 50%;
background: var(--accentColor);
color: white;
border: none;
cursor: pointer;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
z-index: 99;
}
.back-to-top.show {
opacity: 1;
visibility: visible;
}
.back-to-top:hover {
background: var(--accentHover);
transform: translateY(-3px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
/* Loading spinner */
.loading-spinner {
display: inline-block;
width: 1rem;
height: 1rem;
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
margin-right: 0.5rem;
}
/* Responsive Styles */
@media screen and (max-width: 1000px) {
:root {
--sectionPadding: 5rem 0;
}
p {
font-size: 0.95rem;
line-height: 1.7;
}
.hero-name {
font-size: 3rem;
}
.grid-3 {
gap: 2rem;
}
.skills-list {
grid-template-columns: 1fr;
}
.contact {
gap: 2rem;
}
}
@media screen and (max-width: 825px) {
/* Burger Menu */
.burger {
display: block;
cursor: pointer;
}
.toggle-burger .line-1 {
transform: rotate(-45deg) translate(-5px, 7px);
}
.toggle-burger .line-2 {
opacity: 0;
}
.toggle-burger .line-3 {
transform: rotate(45deg) translate(-5px, -7px);
}
/* Navigation */
nav {
position: fixed;
width: 60%;
right: 0;
top: 0;
height: 100vh;
flex-direction: column;
background: var(--primaryBackgroundColor);
border-left: 1px solid var(--borderColor);
z-index: 9;
transform: translateX(100%);
transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
padding: 6rem 2rem;
box-shadow: -10px 0 30px rgba(0, 0, 0, 0.1);
}
nav ul {
flex-direction: column;
gap: 2.5rem;
}
.nav-active {
transform: translateX(0);
}
:root {
--sectionPadding: 4rem 0;
}
/* Titles */
.section-title {
font-size: 2rem;
margin: 0.6rem 0 3rem;
}
.pre-title {
font-size: 0.85rem;
}
/* Hero Section */
#hero {
grid-template-columns: 1fr;
height: auto;
padding: 4rem 20px;
}
.hero-right {
order: -1;
margin-bottom: 3rem;
}
.hero-right img {
width: 80%;
max-width: 400px;
}
.hero-left {
text-align: center;
}
.hero-name {
font-size: 2.5rem;
}
.social-links {
justify-content: center;
}
/* Skills Section */
.skills-grid {
gap: 2rem;
}
.education {
margin-bottom: 2rem;
}
/* Footer */
footer {
padding: 3rem 0;
}
}
@media screen and (max-width: 640px) {
/* Titles */
.section-title {
font-size: 1.8rem;
margin-bottom: 2.5rem;
}
.pre-title {
font-size: 0.8rem;
letter-spacing: 0.2rem;
}
/* Hero */
.hero-name {
font-size: 2.2rem;
}
/* Services */
.service {
padding: 2rem 1.5rem;
}
/* Portfolio */
.portfolio-cover {
height: 200px;
}
/* Contact */
.contact-item {
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
.contact-item-icon {
width: 50px;
height: 50px;
}
/* Footer */
.footer-icons {
gap: 1rem;
}
}
@media screen and (max-width: 480px) {
:root {
--sectionPadding: 3.5rem 0;
}
/* Navigation */
nav {
width: 80%;
}
/* Hero */
.hero-name {
font-size: 2rem;
}
.hero-image-container {
width: 220px;
height: 220px;
}
/* Portfolio */
.grid-3 {
grid-template-columns: 1fr;
}
/* Skills */
.skills-grid {
grid-template-columns: 1fr;
}
/* Contact Form */
.contact-form input,
.contact-form textarea {
padding: 0.8rem 1.2rem;
}
/* Footer */
footer p {
font-size: 0.9rem;
}
}
/* Special height adjustments for mobile */
@media screen and (max-height: 700px) and (orientation: landscape) {
#hero {
height: auto;
padding: 4rem 20px;
}
.hero-right img {
width: 50%;
}
nav ul {
gap: 1.5rem;
}
}
@media screen and (max-width: 768px) {
.experience-header {
flex-direction: column;
}
.experience-date {
text-align: left;
}
.experience-skills span {
font-size: 0.8rem;
}
}
@media screen and (max-width: 480px) {
.experience-item {
padding: 1.5rem;
}
.education-item {
margin-bottom: 2rem;
}
}
/* Dark mode preference */
/*
@media (prefers-color-scheme: dark) {
:root {
--primaryTextColor: #f7fafc;
--secondaryTextColor: #e2e8f0;
--borderColor: #2d3748;
--lineColor: #4a5568;
--primaryBackgroundColor: #1a202c;
--secondaryBackgroundColor: #2d3748;
--thirdBackgroundColor: #4a5568;
}
.service, .portfolio {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2), 0 2px 4px -1px rgba(0, 0, 0, 0.1);
}
}
*/
```
##### 12. edit settings.py
```markdown!
#tambahkan
import os
#tambahkan baris static file dibawah static url
STATIC_URL = 'static/'
STATICFILES_DIRS=[
os.path.join(BASE_DIR, 'static')
]
```
##### 13. buat main.js
```markdown!
document.addEventListener('DOMContentLoaded', function() {
// Mobile Navigation Toggle (tetap sama)
const burger = document.querySelector('.burger');
const nav = document.querySelector('nav');
burger.addEventListener('click', function() {
nav.classList.toggle('active');
burger.classList.toggle('active');
document.body.classList.toggle('no-scroll');
});
// Close mobile menu when clicking on nav links (tetap sama)
const navLinks = document.querySelectorAll('nav ul li a');
navLinks.forEach(link => {
link.addEventListener('click', () => {
nav.classList.remove('active');
burger.classList.remove('active');
document.body.classList.remove('no-scroll');
});
});
// Smooth scrolling for anchor links (diperbarui)
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
if (targetId === '#') return;
const targetElement = document.querySelector(targetId);
if (targetElement) {
window.scrollTo({
top: targetElement.offsetTop - 100, // Diubah dari 80 ke 100 untuk spacing lebih baik
behavior: 'smooth'
});
}
});
});
// Active section highlighting (diperbarui)
const sections = document.querySelectorAll('section[data-section]'); // Hanya section dengan atribut data-section
const navItems = document.querySelectorAll('nav ul li a');
window.addEventListener('scroll', function() {
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop;
const sectionHeight = section.clientHeight;
if (pageYOffset >= (sectionTop - 300)) {
current = section.getAttribute('id');
}
});
navItems.forEach(item => {
item.classList.remove('active');
if (item.getAttribute('href') === `#${current}`) {
item.classList.add('active');
// Tambahkan animasi untuk nav item aktif
item.style.transform = 'translateY(-3px)';
setTimeout(() => {
item.style.transform = '';
}, 300);
}
});
});
// Form submission (diperbarui dengan animasi lebih smooth)
const contactForm = document.querySelector('.contact-form');
if (contactForm) {
contactForm.addEventListener('submit', function(e) {
e.preventDefault();
const submitBtn = this.querySelector('.btn-submit');
const originalBtnText = submitBtn.innerHTML;
// Animasi loading yang lebih halus
submitBtn.innerHTML = '<span class="loading-spinner"></span> Sending...';
submitBtn.disabled = true;
submitBtn.style.transform = 'scale(0.98)';
// Simulasi pengiriman form
setTimeout(() => {
submitBtn.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg> Sent!';
submitBtn.style.transform = 'scale(1)';
// Reset form dengan animasi
setTimeout(() => {
contactForm.reset();
submitBtn.innerHTML = originalBtnText;
submitBtn.disabled = false;
// Notifikasi sukses dengan animasi
const successMsg = document.createElement('div');
successMsg.className = 'form-success';
successMsg.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
<polyline points="22 4 12 14.01 9 11.01"></polyline>
</svg>
<span>Message sent successfully!</span>
`;
contactForm.appendChild(successMsg);
setTimeout(() => {
successMsg.style.opacity = '0';
setTimeout(() => {
successMsg.remove();
}, 500);
}, 3000);
}, 1500);
}, 2000);
});
}
// Back to top button behavior (ditambahkan)
const backToTopBtn = document.createElement('button');
backToTopBtn.className = 'back-to-top';
backToTopBtn.innerHTML = '↑';
backToTopBtn.setAttribute('aria-label', 'Back to top');
document.body.appendChild(backToTopBtn);
// Sticky navbar on scroll
window.addEventListener('scroll', function() {
const nav = document.querySelector('.nav');
if (window.scrollY > 50) {
nav.style.padding = '1rem 0';
nav.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.1)';
} else {
nav.style.padding = '2rem 0';
nav.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.1)';
}
});
backToTopBtn.addEventListener('click', function() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
// Tambahkan efek klik
this.style.transform = 'scale(0.9)';
setTimeout(() => {
this.style.transform = '';
}, 200);
});
document.querySelectorAll('[data-animate]').forEach((el, i) => {
el.style.setProperty('--i', i);
});
// Animasi scroll (diperbarui)
const animateOnScroll = function() {
const elements = document.querySelectorAll('[data-animate]');
const windowHeight = window.innerHeight;
elements.forEach(element => {
const elementPosition = element.getBoundingClientRect().top;
const animationPoint = windowHeight - 150;
if (elementPosition < animationPoint) {
element.style.opacity = '1';
element.style.transform = 'translateY(0)';
}
});
};
// Inisialisasi animasi
window.addEventListener('load', animateOnScroll);
window.addEventListener('scroll', animateOnScroll);
// Tambahkan atribut data-animate ke elemen yang perlu dianimasikan
document.querySelectorAll('.service, .portfolio, .experience-item, .education-item, .contact-item').forEach((el, i) => {
el.setAttribute('data-animate', '');
el.style.transitionDelay = `${i * 0.1}s`;
});
});
```
14. tambahkan file pdf untuk resume dan sertifikat magang

15. edit views.py base
```markdown!
from django.shortcuts import render
def index(request):
return render(request, 'index.html')
```
16.edit urls.py di portofolioku
```markdown!
from django.urls import path
from base import views
urlpatterns = [
path('', views.index, name='index'),
]
```
## Deploy ke docker
1. siapkan file requirenment.txt
```markdown!
asgiref==3.8.1
dj-database-url==2.3.0
Django==5.2
django-crispy-forms==2.4
gunicorn==23.0.0
packaging==25.0
pillow==11.2.1
psycopg2-binary==2.9.10
sqlparse==0.5.3
typing_extensions==4.13.2
tzdata==2025.2
whitenoise==6.9.0
```
2. buat dockerfile di direktori yang setara dengan manage.py
```markdown!
# Gunakan base image Python yang ringan
FROM python:3.11-slim
# Set direktori kerja di dalam container
WORKDIR /app
# Salin file requirements dan install dependencies terlebih dahulu
COPY requirements.txt .
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
# Salin seluruh isi project ke dalam container
COPY . /app
# Jalankan collectstatic untuk mengumpulkan static files
RUN python manage.py collectstatic --noinput
# Expose port Gunicorn
EXPOSE 8000
# Jalankan server Gunicorn untuk production
CMD ["gunicorn", "portofolioku.wsgi:application", "--bind", "0.0.0.0:8000"]
```
3. buat file docker-compose.yml
```markdown!
services:
web:
build: .
container_name: portofolioku_web
command: gunicorn portofolioku.wsgi:application --bind 0.0.0.0:8000
ports:
- "8000:8000"
volumes:
- .:/app
env_file:
- .env
```
4. buat file .env
```markdown!
DEBUG=False
```
5. tambahkan configan berikut di settings.py
```markdown!
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
...
]
```
```markdown!
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles' # penting untuk collectstatic
# Optional: Enable compression and caching
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
```
6. build dan jalankan dengan docker compose
```markdown!
docker-compose up -d --build
```
7. akses web
```markdown!
http://localhost:8000
```
8. mematikan dan menghapus container
```markdown!
docker-compose down
```