951 lines
29 KiB
Vue
951 lines
29 KiB
Vue
<script setup>
|
|
import { ref, computed } from 'vue';
|
|
|
|
// User profile data
|
|
const userProfile = ref({
|
|
personal: {
|
|
name: 'Alex Johnson',
|
|
title: 'Senior Frontend Developer',
|
|
email: 'alex.johnson@example.com',
|
|
phone: '+1 (555) 123-4567',
|
|
location: 'San Francisco, CA',
|
|
about: 'Passionate frontend developer with 6+ years of experience building responsive and user-friendly web applications. Specialized in Vue.js and modern JavaScript frameworks.',
|
|
avatar: null, // Will be generated from initials if null
|
|
},
|
|
experience: [
|
|
{
|
|
id: 1,
|
|
title: 'Senior Frontend Developer',
|
|
company: 'TechInnovate Solutions',
|
|
location: 'San Francisco, CA',
|
|
startDate: '2023-01',
|
|
endDate: null, // null means current
|
|
isCurrent: true,
|
|
description: 'Lead the frontend development team in building modern web applications using Vue.js. Implemented component libraries and design systems that improved development efficiency by 35%.',
|
|
achievements: [
|
|
'Reduced page load time by 40% through code optimization and lazy loading',
|
|
'Implemented comprehensive unit and integration testing, achieving 90% code coverage',
|
|
'Mentored junior developers and conducted code reviews to maintain high code quality'
|
|
]
|
|
},
|
|
{
|
|
id: 2,
|
|
title: 'Frontend Developer',
|
|
company: 'WebSolutions Inc.',
|
|
location: 'Boston, MA',
|
|
startDate: '2020-03',
|
|
endDate: '2022-12',
|
|
isCurrent: false,
|
|
description: 'Developed responsive web applications using Vue.js and Nuxt. Collaborated with UX/UI designers to implement pixel-perfect interfaces.',
|
|
achievements: [
|
|
'Built a component library that was used across multiple projects',
|
|
'Implemented state management using Vuex that simplified data flow',
|
|
'Integrated third-party APIs and services to enhance application functionality'
|
|
]
|
|
},
|
|
{
|
|
id: 3,
|
|
title: 'Junior Web Developer',
|
|
company: 'Digital Creations',
|
|
location: 'Remote',
|
|
startDate: '2018-06',
|
|
endDate: '2020-02',
|
|
isCurrent: false,
|
|
description: 'Developed and maintained client websites using HTML, CSS, and JavaScript. Collaborated with the design team to implement responsive layouts.',
|
|
achievements: [
|
|
'Converted 15+ static websites to responsive designs',
|
|
'Implemented SEO best practices that improved client search rankings',
|
|
'Created custom WordPress themes and plugins for client websites'
|
|
]
|
|
}
|
|
],
|
|
education: [
|
|
{
|
|
id: 1,
|
|
degree: 'Master of Science in Computer Science',
|
|
institution: 'Stanford University',
|
|
location: 'Stanford, CA',
|
|
startDate: '2016-09',
|
|
endDate: '2018-05',
|
|
description: 'Focused on web technologies and human-computer interaction. Thesis on improving frontend performance in single-page applications.'
|
|
},
|
|
{
|
|
id: 2,
|
|
degree: 'Bachelor of Science in Computer Science',
|
|
institution: 'University of Washington',
|
|
location: 'Seattle, WA',
|
|
startDate: '2012-09',
|
|
endDate: '2016-05',
|
|
description: 'Graduated with honors. Coursework included web development, algorithms, data structures, and software engineering principles.'
|
|
}
|
|
],
|
|
skills: [
|
|
{ name: 'Vue.js', level: 95 },
|
|
{ name: 'JavaScript', level: 90 },
|
|
{ name: 'HTML/CSS', level: 95 },
|
|
{ name: 'SCSS/SASS', level: 85 },
|
|
{ name: 'TypeScript', level: 80 },
|
|
{ name: 'React', level: 75 },
|
|
{ name: 'Node.js', level: 70 },
|
|
{ name: 'Git', level: 85 },
|
|
{ name: 'Webpack', level: 75 },
|
|
{ name: 'Jest', level: 80 },
|
|
{ name: 'RESTful APIs', level: 85 },
|
|
{ name: 'GraphQL', level: 70 }
|
|
],
|
|
projects: [
|
|
{
|
|
id: 1,
|
|
title: 'E-commerce Dashboard',
|
|
description: 'A comprehensive dashboard for e-commerce businesses to track sales, inventory, and customer data in real-time.',
|
|
technologies: ['Vue.js', 'Vuex', 'Chart.js', 'Firebase'],
|
|
link: 'https://github.com/alexjohnson/ecommerce-dashboard',
|
|
image: null
|
|
},
|
|
{
|
|
id: 2,
|
|
title: 'Task Management App',
|
|
description: 'A collaborative task management application with real-time updates, file sharing, and team communication features.',
|
|
technologies: ['Vue.js', 'Node.js', 'Socket.io', 'MongoDB'],
|
|
link: 'https://github.com/alexjohnson/task-manager',
|
|
image: null
|
|
},
|
|
{
|
|
id: 3,
|
|
title: 'Weather Forecast App',
|
|
description: 'A weather application that provides detailed forecasts, historical data, and customizable alerts based on user location.',
|
|
technologies: ['Vue.js', 'OpenWeatherMap API', 'Geolocation API', 'PWA'],
|
|
link: 'https://github.com/alexjohnson/weather-app',
|
|
image: null
|
|
}
|
|
],
|
|
certifications: [
|
|
{
|
|
id: 1,
|
|
name: 'Vue.js Advanced Developer',
|
|
issuer: 'Vue Mastery',
|
|
date: '2023-04',
|
|
expires: '2026-04',
|
|
credentialId: 'VM-ADV-2023-1234',
|
|
link: 'https://vuemastery.com/cert/VM-ADV-2023-1234'
|
|
},
|
|
{
|
|
id: 2,
|
|
name: 'Frontend Web Developer Nanodegree',
|
|
issuer: 'Udacity',
|
|
date: '2021-08',
|
|
expires: null, // No expiration
|
|
credentialId: 'UD-FWD-2021-5678',
|
|
link: 'https://udacity.com/cert/UD-FWD-2021-5678'
|
|
},
|
|
{
|
|
id: 3,
|
|
name: 'JavaScript Algorithms and Data Structures',
|
|
issuer: 'freeCodeCamp',
|
|
date: '2020-11',
|
|
expires: null, // No expiration
|
|
credentialId: 'FCC-JADS-2020-9012',
|
|
link: 'https://freecodecamp.org/cert/FCC-JADS-2020-9012'
|
|
}
|
|
],
|
|
languages: [
|
|
{ name: 'English', proficiency: 'Native' },
|
|
{ name: 'Spanish', proficiency: 'Intermediate' },
|
|
{ name: 'French', proficiency: 'Basic' }
|
|
],
|
|
socialLinks: {
|
|
github: 'https://github.com/alexjohnson',
|
|
linkedin: 'https://linkedin.com/in/alexjohnson',
|
|
twitter: 'https://twitter.com/alexjohnson',
|
|
portfolio: 'https://alexjohnson.dev'
|
|
},
|
|
preferences: {
|
|
jobTypes: ['Full-time', 'Remote'],
|
|
locations: ['San Francisco, CA', 'Remote'],
|
|
salary: '$120,000 - $150,000',
|
|
availableFrom: '2025-06-01',
|
|
willingToRelocate: true,
|
|
industries: ['Technology', 'E-commerce', 'Healthcare', 'Education']
|
|
},
|
|
resume: {
|
|
url: '/path/to/resume.pdf',
|
|
lastUpdated: '2025-02-15'
|
|
}
|
|
});
|
|
|
|
// Computed properties for display
|
|
const fullName = computed(() => userProfile.value.personal.name);
|
|
const initials = computed(() => {
|
|
const nameParts = userProfile.value.personal.name.split(' ');
|
|
return nameParts.map(part => part[0]).join('');
|
|
});
|
|
|
|
// Format date function
|
|
const formatDate = (dateString) => {
|
|
if (!dateString) return 'Present';
|
|
|
|
const date = new Date(dateString);
|
|
return new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short' }).format(date);
|
|
};
|
|
|
|
// Calculate experience duration
|
|
const calculateDuration = (startDate, endDate) => {
|
|
const start = new Date(startDate);
|
|
const end = endDate ? new Date(endDate) : new Date();
|
|
|
|
const years = end.getFullYear() - start.getFullYear();
|
|
const months = end.getMonth() - start.getMonth();
|
|
|
|
let duration = '';
|
|
if (years > 0) {
|
|
duration += `${years} year${years !== 1 ? 's' : ''}`;
|
|
}
|
|
|
|
if (months > 0 || (months === 0 && years === 0)) {
|
|
if (duration) duration += ', ';
|
|
duration += `${months} month${months !== 1 ? 's' : ''}`;
|
|
}
|
|
|
|
return duration;
|
|
};
|
|
|
|
// Total years of experience
|
|
const totalExperience = computed(() => {
|
|
let totalMonths = 0;
|
|
|
|
userProfile.value.experience.forEach(exp => {
|
|
const startDate = new Date(exp.startDate);
|
|
const endDate = exp.endDate ? new Date(exp.endDate) : new Date();
|
|
|
|
const years = endDate.getFullYear() - startDate.getFullYear();
|
|
const months = endDate.getMonth() - startDate.getMonth();
|
|
|
|
totalMonths += years * 12 + months;
|
|
});
|
|
|
|
const years = Math.floor(totalMonths / 12);
|
|
const months = totalMonths % 12;
|
|
|
|
let result = '';
|
|
if (years > 0) {
|
|
result += `${years} year${years !== 1 ? 's' : ''}`;
|
|
}
|
|
|
|
if (months > 0) {
|
|
if (result) result += ' ';
|
|
result += `${months} month${months !== 1 ? 's' : ''}`;
|
|
}
|
|
|
|
return result;
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="profile-container">
|
|
<div class="profile-header">
|
|
<div class="profile-avatar" v-if="userProfile.personal.avatar">
|
|
<img :src="userProfile.personal.avatar" alt="Profile avatar" />
|
|
</div>
|
|
<div class="profile-avatar profile-avatar-initials" v-else>
|
|
{{ initials }}
|
|
</div>
|
|
|
|
<div class="profile-header-info">
|
|
<h1 class="profile-name">{{ userProfile.personal.name }}</h1>
|
|
<h2 class="profile-title">{{ userProfile.personal.title }}</h2>
|
|
<div class="profile-location">
|
|
<span class="location-icon">📍</span>
|
|
<span>{{ userProfile.personal.location }}</span>
|
|
</div>
|
|
|
|
<div class="profile-contact">
|
|
<div class="contact-item">
|
|
<span class="contact-icon">📧</span>
|
|
<a :href="`mailto:${userProfile.personal.email}`">{{ userProfile.personal.email }}</a>
|
|
</div>
|
|
<div class="contact-item">
|
|
<span class="contact-icon">📱</span>
|
|
<a :href="`tel:${userProfile.personal.phone}`">{{ userProfile.personal.phone }}</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="profile-social">
|
|
<a v-if="userProfile.socialLinks.github" :href="userProfile.socialLinks.github" target="_blank" class="social-link">
|
|
GitHub
|
|
</a>
|
|
<a v-if="userProfile.socialLinks.linkedin" :href="userProfile.socialLinks.linkedin" target="_blank" class="social-link">
|
|
LinkedIn
|
|
</a>
|
|
<a v-if="userProfile.socialLinks.twitter" :href="userProfile.socialLinks.twitter" target="_blank" class="social-link">
|
|
Twitter
|
|
</a>
|
|
<a v-if="userProfile.socialLinks.portfolio" :href="userProfile.socialLinks.portfolio" target="_blank" class="social-link">
|
|
Portfolio
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="profile-actions">
|
|
<button class="action-button primary-button">
|
|
<span class="action-icon">📝</span>
|
|
<span>Edit Profile</span>
|
|
</button>
|
|
<button class="action-button secondary-button">
|
|
<span class="action-icon">📄</span>
|
|
<span>Download Resume</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="profile-tabs">
|
|
<div class="tab-navigation">
|
|
<button class="tab-button active">Overview</button>
|
|
<button class="tab-button">Experience</button>
|
|
<button class="tab-button">Education</button>
|
|
<button class="tab-button">Skills</button>
|
|
<button class="tab-button">Projects</button>
|
|
<button class="tab-button">Preferences</button>
|
|
</div>
|
|
|
|
<div class="tab-content">
|
|
<!-- Overview Tab -->
|
|
<div class="tab-section">
|
|
<div class="section-container">
|
|
<h2 class="section-title">About Me</h2>
|
|
<p class="about-text">{{ userProfile.personal.about }}</p>
|
|
|
|
<div class="overview-stats">
|
|
<div class="stat-item">
|
|
<div class="stat-value">{{ totalExperience }}</div>
|
|
<div class="stat-label">Experience</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-value">{{ userProfile.skills.length }}</div>
|
|
<div class="stat-label">Skills</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-value">{{ userProfile.projects.length }}</div>
|
|
<div class="stat-label">Projects</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-value">{{ userProfile.certifications.length }}</div>
|
|
<div class="stat-label">Certifications</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2 class="section-title">Experience Highlights</h2>
|
|
<div class="experience-highlights">
|
|
<div v-for="exp in userProfile.experience.slice(0, 2)" :key="exp.id" class="highlight-item">
|
|
<div class="highlight-header">
|
|
<h3 class="highlight-title">{{ exp.title }}</h3>
|
|
<div class="highlight-company">{{ exp.company }}</div>
|
|
<div class="highlight-duration">
|
|
{{ formatDate(exp.startDate) }} - {{ formatDate(exp.endDate) }}
|
|
<span class="duration-text">({{ calculateDuration(exp.startDate, exp.endDate) }})</span>
|
|
</div>
|
|
</div>
|
|
<p class="highlight-description">{{ exp.description }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<h2 class="section-title">Top Skills</h2>
|
|
<div class="skills-highlights">
|
|
<div v-for="skill in userProfile.skills.slice(0, 6)" :key="skill.name" class="skill-item">
|
|
<div class="skill-info">
|
|
<div class="skill-name">{{ skill.name }}</div>
|
|
<div class="skill-level">{{ skill.level }}%</div>
|
|
</div>
|
|
<div class="skill-bar">
|
|
<div class="skill-progress" :style="{ width: `${skill.level}%` }"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2 class="section-title">Featured Projects</h2>
|
|
<div class="projects-highlights">
|
|
<div v-for="project in userProfile.projects.slice(0, 2)" :key="project.id" class="project-item">
|
|
<div class="project-image" v-if="project.image">
|
|
<img :src="project.image" alt="Project thumbnail" />
|
|
</div>
|
|
<div class="project-image project-placeholder" v-else>
|
|
<span class="project-icon">🚀</span>
|
|
</div>
|
|
|
|
<div class="project-info">
|
|
<h3 class="project-title">{{ project.title }}</h3>
|
|
<p class="project-description">{{ project.description }}</p>
|
|
<div class="project-technologies">
|
|
<span v-for="(tech, index) in project.technologies" :key="index" class="tech-tag">
|
|
{{ tech }}
|
|
</span>
|
|
</div>
|
|
<a v-if="project.link" :href="project.link" target="_blank" class="project-link">
|
|
View Project
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
@use 'sass:color';
|
|
|
|
/* Global transition properties for smoother theme switching */
|
|
.profile-container * {
|
|
transition: color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
background-color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
border-color var(--theme-transition-duration) var(--theme-transition-timing);
|
|
}
|
|
.profile-container {
|
|
width: 100%;
|
|
margin: 0;
|
|
background-color: var(--card-bg, #fff);
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
overflow: hidden;
|
|
color: var(--text-color, #333);
|
|
|
|
.profile-header {
|
|
display: flex;
|
|
padding: 2rem;
|
|
border-bottom: 1px solid var(--card-border, #eee);
|
|
|
|
@media (max-width: 768px) {
|
|
flex-direction: column;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.profile-avatar {
|
|
width: 120px;
|
|
height: 120px;
|
|
border-radius: 50%;
|
|
overflow: hidden;
|
|
margin-right: 2rem;
|
|
flex-shrink: 0;
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
|
|
&.profile-avatar-initials {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: var(--primary-color, #3498db);
|
|
color: white;
|
|
font-size: 2.5rem;
|
|
font-weight: 700;
|
|
}
|
|
}
|
|
|
|
.profile-header-info {
|
|
flex: 1;
|
|
|
|
.profile-name {
|
|
font-size: 1.8rem;
|
|
margin: 0 0 0.5rem;
|
|
color: var(--text-color, #333);
|
|
}
|
|
|
|
.profile-title {
|
|
font-size: 1.2rem;
|
|
font-weight: 500;
|
|
color: var(--text-color-secondary, #555);
|
|
margin: 0 0 1rem;
|
|
}
|
|
|
|
.profile-location {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 1rem;
|
|
color: var(--text-color-secondary, #777);
|
|
|
|
.location-icon {
|
|
margin-right: 0.5rem;
|
|
}
|
|
}
|
|
|
|
.profile-contact {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1rem;
|
|
margin-bottom: 1rem;
|
|
|
|
.contact-item {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.contact-icon {
|
|
margin-right: 0.5rem;
|
|
}
|
|
|
|
a {
|
|
color: var(--primary-color, #3498db);
|
|
text-decoration: none;
|
|
|
|
&:hover {
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.profile-social {
|
|
display: flex;
|
|
gap: 1rem;
|
|
|
|
.social-link {
|
|
color: var(--primary-color, #3498db);
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
|
|
&:hover {
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.profile-actions {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.75rem;
|
|
|
|
@media (max-width: 768px) {
|
|
flex-direction: row;
|
|
}
|
|
|
|
.action-button {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 0.75rem 1.25rem;
|
|
border-radius: 8px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
|
|
.action-icon {
|
|
margin-right: 0.5rem;
|
|
}
|
|
|
|
&.primary-button {
|
|
background-color: var(--primary-color, #3498db);
|
|
color: white;
|
|
border: none;
|
|
|
|
&:hover {
|
|
background-color: color.adjust(#3498db, $lightness: -10%);
|
|
}
|
|
}
|
|
|
|
&.secondary-button {
|
|
background-color: transparent;
|
|
color: var(--primary-color, #3498db);
|
|
border: 1px solid var(--primary-color, #3498db);
|
|
|
|
&:hover {
|
|
background-color: rgba(52, 152, 219, 0.1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.profile-tabs {
|
|
.tab-navigation {
|
|
display: flex;
|
|
border-bottom: 1px solid var(--card-border, #eee);
|
|
overflow-x: auto;
|
|
background-color: var(--card-bg, #fff);
|
|
|
|
&::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
.tab-button {
|
|
padding: 1rem 1.5rem;
|
|
background: transparent;
|
|
border: none;
|
|
border-bottom: 2px solid transparent;
|
|
font-weight: 500;
|
|
color: var(--text-color-secondary, #777);
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
transition: all 0.2s ease;
|
|
|
|
&.active {
|
|
color: var(--primary-color, #3498db);
|
|
border-bottom-color: var(--primary-color, #3498db);
|
|
}
|
|
|
|
&:hover:not(.active) {
|
|
color: var(--text-color, #333);
|
|
background-color: rgba(0, 0, 0, 0.03);
|
|
}
|
|
}
|
|
}
|
|
|
|
.tab-content {
|
|
padding: 2rem;
|
|
|
|
.section-title {
|
|
font-size: 1.4rem;
|
|
margin: 0 0 1.5rem;
|
|
color: var(--text-color, #333);
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 1px solid var(--card-border, #eee);
|
|
}
|
|
|
|
.about-text {
|
|
font-size: 1rem;
|
|
line-height: 1.6;
|
|
color: var(--text-color-secondary, #555);
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.overview-stats {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1.5rem;
|
|
margin-bottom: 2rem;
|
|
|
|
.stat-item {
|
|
flex: 1;
|
|
min-width: 120px;
|
|
background-color: var(--card-bg-secondary, #f9f9f9);
|
|
border: 1px solid var(--card-border, #eee);
|
|
transition: background-color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
border-color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
box-shadow var(--theme-transition-duration) var(--theme-transition-timing);
|
|
padding: 1.25rem;
|
|
border-radius: 8px;
|
|
text-align: center;
|
|
|
|
.stat-value {
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
color: var(--primary-color, #3498db);
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.9rem;
|
|
color: var(--text-color-tertiary, #777);
|
|
}
|
|
}
|
|
}
|
|
|
|
.experience-highlights {
|
|
margin-bottom: 2rem;
|
|
|
|
.highlight-item {
|
|
padding: 1.25rem;
|
|
background-color: var(--card-bg-secondary, #f9f9f9);
|
|
border: 1px solid var(--card-border, #eee);
|
|
transition: background-color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
border-color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
box-shadow var(--theme-transition-duration) var(--theme-transition-timing);
|
|
border-radius: 8px;
|
|
margin-bottom: 1rem;
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.highlight-header {
|
|
margin-bottom: 1rem;
|
|
|
|
.highlight-title {
|
|
font-size: 1.1rem;
|
|
font-weight: 600;
|
|
margin: 0 0 0.25rem;
|
|
color: var(--text-color, #333);
|
|
}
|
|
|
|
.highlight-company {
|
|
font-size: 0.95rem;
|
|
color: var(--text-color-secondary, #555);
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.highlight-duration {
|
|
font-size: 0.85rem;
|
|
color: var(--text-color-tertiary, #999);
|
|
|
|
.duration-text {
|
|
margin-left: 0.5rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
.highlight-description {
|
|
font-size: 0.95rem;
|
|
line-height: 1.5;
|
|
color: var(--text-color-secondary, #555);
|
|
}
|
|
}
|
|
}
|
|
|
|
.skills-highlights {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 1rem;
|
|
margin-bottom: 2rem;
|
|
|
|
.skill-item {
|
|
.skill-info {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-bottom: 0.5rem;
|
|
|
|
.skill-name {
|
|
font-size: 0.95rem;
|
|
font-weight: 500;
|
|
color: var(--text-color, #333);
|
|
}
|
|
|
|
.skill-level {
|
|
font-size: 0.85rem;
|
|
color: var(--text-color-tertiary, #777);
|
|
}
|
|
}
|
|
|
|
.skill-bar {
|
|
height: 8px;
|
|
background-color: var(--card-bg-secondary, #f9f9f9);
|
|
transition: background-color var(--theme-transition-duration) var(--theme-transition-timing);
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
|
|
.skill-progress {
|
|
height: 100%;
|
|
background-color: var(--primary-color, #3498db);
|
|
border-radius: 4px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.projects-highlights {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
gap: 1.5rem;
|
|
|
|
.project-item {
|
|
background-color: var(--card-bg-secondary, #f9f9f9);
|
|
transition: background-color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
border-color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
box-shadow var(--theme-transition-duration) var(--theme-transition-timing);
|
|
border-radius: 8px;
|
|
border: 1px solid var(--card-border, #eee);
|
|
overflow: hidden;
|
|
|
|
.project-image {
|
|
height: 160px;
|
|
background-color: var(--card-bg-secondary, #f9f9f9);
|
|
transition: background-color var(--theme-transition-duration) var(--theme-transition-timing),
|
|
border-color var(--theme-transition-duration) var(--theme-transition-timing);
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
}
|
|
|
|
&.project-placeholder {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: var(--primary-color-light, rgba(52, 152, 219, 0.1));
|
|
|
|
.project-icon {
|
|
font-size: 3rem;
|
|
color: var(--primary-color, #3498db);
|
|
}
|
|
}
|
|
}
|
|
|
|
.project-info {
|
|
padding: 1.25rem;
|
|
|
|
.project-title {
|
|
font-size: 1.1rem;
|
|
font-weight: 600;
|
|
margin: 0 0 0.75rem;
|
|
color: var(--text-color, #333);
|
|
}
|
|
|
|
.project-description {
|
|
font-size: 0.9rem;
|
|
line-height: 1.5;
|
|
color: var(--text-color-secondary, #555);
|
|
margin-bottom: 1rem;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 3;
|
|
line-clamp: 3;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
transition: color 0.3s ease;
|
|
}
|
|
|
|
.project-technologies {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
margin-bottom: 1rem;
|
|
|
|
.tech-tag {
|
|
font-size: 0.8rem;
|
|
padding: 0.25rem 0.6rem;
|
|
border-radius: 16px;
|
|
background-color: var(--tag-bg, rgba(52, 152, 219, 0.1));
|
|
color: var(--primary-color, #3498db);
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
background-color: var(--primary-color-light, rgba(52, 152, 219, 0.2));
|
|
}
|
|
}
|
|
}
|
|
|
|
.project-link {
|
|
display: inline-block;
|
|
color: var(--primary-color, #3498db);
|
|
text-decoration: none;
|
|
font-size: 0.9rem;
|
|
font-weight: 500;
|
|
transition: all 0.2s ease;
|
|
|
|
&:hover {
|
|
text-decoration: underline;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dark mode styles
|
|
@media (prefers-color-scheme: dark) {
|
|
.profile-container {
|
|
background-color: var(--card-bg, #222);
|
|
color: var(--text-color, #eee);
|
|
|
|
.profile-header {
|
|
border-bottom-color: var(--card-border, #444);
|
|
}
|
|
|
|
.profile-header-info {
|
|
.profile-name, .profile-title {
|
|
color: var(--text-color, #eee);
|
|
}
|
|
|
|
.profile-location, .contact-item {
|
|
color: var(--text-color-secondary, #bbb);
|
|
}
|
|
}
|
|
|
|
.tab-navigation {
|
|
border-bottom-color: var(--card-border, #444);
|
|
|
|
.tab-button {
|
|
color: var(--text-color-secondary, #bbb);
|
|
|
|
&:hover:not(.active) {
|
|
background-color: rgba(255, 255, 255, 0.05);
|
|
}
|
|
}
|
|
}
|
|
|
|
.section-title {
|
|
color: var(--text-color, #eee);
|
|
border-bottom-color: var(--card-border, #444);
|
|
}
|
|
|
|
.about-text,
|
|
.highlight-description,
|
|
.project-description {
|
|
color: var(--text-color-secondary, #bbb);
|
|
}
|
|
|
|
.stat-label {
|
|
color: var(--text-color-secondary, #bbb) !important;
|
|
}
|
|
|
|
.overview-stats .stat-item,
|
|
.experience-highlights .highlight-item,
|
|
.tab-content .stat-item {
|
|
background-color: var(--card-bg, #2a2a2a);
|
|
border-color: var(--card-border, #444);
|
|
}
|
|
|
|
.projects-highlights .project-item {
|
|
background-color: var(--card-bg, #2a2a2a);
|
|
border-color: var(--card-border, #444);
|
|
}
|
|
|
|
.project-info {
|
|
background-color: var(--card-bg, #2a2a2a);
|
|
}
|
|
|
|
.highlight-header {
|
|
.highlight-title {
|
|
color: var(--text-color, #eee);
|
|
}
|
|
|
|
.highlight-company {
|
|
color: var(--text-color-secondary, #bbb);
|
|
}
|
|
}
|
|
|
|
.skills-highlights {
|
|
.skill-item .skill-info {
|
|
.skill-name {
|
|
color: var(--text-color, #eee);
|
|
}
|
|
|
|
.skill-level {
|
|
color: var(--text-color-secondary, #bbb);
|
|
}
|
|
}
|
|
|
|
.skill-item .skill-bar {
|
|
background-color: var(--card-bg-secondary, rgba(255, 255, 255, 0.1));
|
|
}
|
|
}
|
|
|
|
.tech-tag {
|
|
background-color: var(--primary-color-light, rgba(52, 152, 219, 0.2));
|
|
color: #64b5f6;
|
|
}
|
|
|
|
.project-image {
|
|
background-color: var(--card-bg, #222);
|
|
border-color: var(--card-border, #444);
|
|
}
|
|
|
|
.project-image.project-placeholder {
|
|
background-color: var(--primary-color-light, rgba(52, 152, 219, 0.2));
|
|
}
|
|
|
|
.project-item {
|
|
border-color: var(--card-border, #444);
|
|
}
|
|
|
|
.project-info .project-title {
|
|
color: var(--text-color, #eee);
|
|
}
|
|
}
|
|
}
|
|
</style>
|