472 lines
11 KiB
Vue
472 lines
11 KiB
Vue
<script setup>
|
|
import { ref } from 'vue';
|
|
|
|
// Sample dashboard data
|
|
const stats = ref({
|
|
applications: 12,
|
|
interviews: 4,
|
|
offers: 1,
|
|
savedJobs: 8
|
|
});
|
|
|
|
const recentActivity = ref([
|
|
{
|
|
id: 1,
|
|
type: 'application',
|
|
company: 'Tech Innovations Inc.',
|
|
position: 'Frontend Developer',
|
|
date: '2025-03-28',
|
|
status: 'Applied'
|
|
},
|
|
{
|
|
id: 2,
|
|
type: 'interview',
|
|
company: 'DataSystems Co.',
|
|
position: 'Backend Engineer',
|
|
date: '2025-03-25',
|
|
status: 'Interview Scheduled'
|
|
},
|
|
{
|
|
id: 3,
|
|
type: 'saved',
|
|
company: 'WebSolutions Ltd.',
|
|
position: 'Full Stack Developer',
|
|
date: '2025-03-23',
|
|
status: 'Saved'
|
|
},
|
|
{
|
|
id: 4,
|
|
type: 'offer',
|
|
company: 'Digital Creations',
|
|
position: 'UI/UX Designer',
|
|
date: '2025-03-20',
|
|
status: 'Offer Received'
|
|
}
|
|
]);
|
|
|
|
const upcomingEvents = ref([
|
|
{
|
|
id: 1,
|
|
title: 'Technical Interview',
|
|
company: 'DataSystems Co.',
|
|
date: '2025-04-02',
|
|
time: '10:00 AM'
|
|
},
|
|
{
|
|
id: 2,
|
|
title: 'Coding Challenge Due',
|
|
company: 'Tech Innovations Inc.',
|
|
date: '2025-04-05',
|
|
time: '11:59 PM'
|
|
},
|
|
{
|
|
id: 3,
|
|
title: 'Follow-up Call',
|
|
company: 'Digital Creations',
|
|
date: '2025-04-07',
|
|
time: '2:30 PM'
|
|
}
|
|
]);
|
|
|
|
const recommendedJobs = ref([
|
|
{
|
|
id: 1,
|
|
title: 'Senior Vue Developer',
|
|
company: 'InnovateTech Solutions',
|
|
location: 'Remote',
|
|
salary: '$140,000 - $170,000',
|
|
matchScore: 95
|
|
},
|
|
{
|
|
id: 2,
|
|
title: 'Frontend Team Lead',
|
|
company: 'WebWorks Inc.',
|
|
location: 'San Francisco, CA',
|
|
salary: '$160,000 - $190,000',
|
|
matchScore: 88
|
|
},
|
|
{
|
|
id: 3,
|
|
title: 'Full Stack Engineer',
|
|
company: 'CloudSystems',
|
|
location: 'New York, NY',
|
|
salary: '$130,000 - $160,000',
|
|
matchScore: 82
|
|
}
|
|
]);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="dashboard">
|
|
<div class="dashboard-grid">
|
|
<!-- Stats Cards -->
|
|
<div class="stats-container">
|
|
<div class="stat-card">
|
|
<div class="stat-value">{{ stats.applications }}</div>
|
|
<div class="stat-label">Applications</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-value">{{ stats.interviews }}</div>
|
|
<div class="stat-label">Interviews</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-value">{{ stats.offers }}</div>
|
|
<div class="stat-label">Offers</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-value">{{ stats.savedJobs }}</div>
|
|
<div class="stat-label">Saved Jobs</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Activity -->
|
|
<div class="dashboard-card activity-card">
|
|
<h3 class="card-title">Recent Activity</h3>
|
|
<div class="activity-list">
|
|
<div v-for="activity in recentActivity" :key="activity.id" class="activity-item">
|
|
<div class="activity-icon" :class="activity.type">
|
|
<span v-if="activity.type === 'application'">📝</span>
|
|
<span v-else-if="activity.type === 'interview'">🗣️</span>
|
|
<span v-else-if="activity.type === 'saved'">⭐</span>
|
|
<span v-else-if="activity.type === 'offer'">🎉</span>
|
|
</div>
|
|
<div class="activity-details">
|
|
<div class="activity-title">{{ activity.position }}</div>
|
|
<div class="activity-company">{{ activity.company }}</div>
|
|
<div class="activity-meta">
|
|
<span class="activity-date">{{ activity.date }}</span>
|
|
<span class="activity-status" :class="activity.type">{{ activity.status }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Upcoming Events -->
|
|
<div class="dashboard-card events-card">
|
|
<h3 class="card-title">Upcoming Events</h3>
|
|
<div class="events-list">
|
|
<div v-for="event in upcomingEvents" :key="event.id" class="event-item">
|
|
<div class="event-date">
|
|
<div class="event-day">{{ new Date(event.date).getDate() }}</div>
|
|
<div class="event-month">{{ new Date(event.date).toLocaleString('default', { month: 'short' }) }}</div>
|
|
</div>
|
|
<div class="event-details">
|
|
<div class="event-title">{{ event.title }}</div>
|
|
<div class="event-company">{{ event.company }}</div>
|
|
<div class="event-time">{{ event.time }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recommended Jobs -->
|
|
<div class="dashboard-card recommended-card">
|
|
<h3 class="card-title">Recommended for You</h3>
|
|
<div class="recommended-list">
|
|
<div v-for="job in recommendedJobs" :key="job.id" class="recommended-item">
|
|
<div class="match-score">{{ job.matchScore }}% Match</div>
|
|
<div class="job-details">
|
|
<div class="job-title">{{ job.title }}</div>
|
|
<div class="job-company">{{ job.company }}</div>
|
|
<div class="job-meta">
|
|
<span class="job-location">{{ job.location }}</span>
|
|
<span class="job-salary">{{ job.salary }}</span>
|
|
</div>
|
|
</div>
|
|
<button class="view-job-btn">View</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.dashboard {
|
|
width: 100%;
|
|
|
|
.dashboard-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 1.5rem;
|
|
|
|
@media (max-width: 768px) {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
|
|
.stats-container {
|
|
grid-column: 1 / -1;
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 1rem;
|
|
|
|
@media (max-width: 768px) {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
}
|
|
}
|
|
|
|
.stat-card {
|
|
background-color: var(--card-bg, #fff);
|
|
border: 1px solid var(--card-border, #ddd);
|
|
border-radius: 8px;
|
|
padding: 1.5rem;
|
|
text-align: center;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
|
|
.stat-value {
|
|
font-size: 2.5rem;
|
|
font-weight: 700;
|
|
color: var(--primary-color);
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.9rem;
|
|
color: var(--text-color);
|
|
opacity: 0.8;
|
|
}
|
|
}
|
|
|
|
.dashboard-card {
|
|
background-color: var(--card-bg, #fff);
|
|
border: 1px solid var(--card-border, #ddd);
|
|
border-radius: 8px;
|
|
padding: 1.5rem;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
|
|
.card-title {
|
|
margin-top: 0;
|
|
margin-bottom: 1rem;
|
|
font-size: 1.2rem;
|
|
font-weight: 600;
|
|
color: var(--text-color);
|
|
border-bottom: 1px solid var(--card-border, #ddd);
|
|
padding-bottom: 0.75rem;
|
|
}
|
|
}
|
|
|
|
.activity-card {
|
|
.activity-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.activity-item {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
padding-bottom: 1rem;
|
|
border-bottom: 1px solid var(--card-border, #eee);
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
padding-bottom: 0;
|
|
}
|
|
}
|
|
|
|
.activity-icon {
|
|
width: 2.5rem;
|
|
height: 2.5rem;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 1rem;
|
|
background-color: rgba(0, 0, 0, 0.05);
|
|
|
|
&.application {
|
|
background-color: rgba(52, 152, 219, 0.1);
|
|
}
|
|
|
|
&.interview {
|
|
background-color: rgba(155, 89, 182, 0.1);
|
|
}
|
|
|
|
&.saved {
|
|
background-color: rgba(241, 196, 15, 0.1);
|
|
}
|
|
|
|
&.offer {
|
|
background-color: rgba(46, 204, 113, 0.1);
|
|
}
|
|
}
|
|
|
|
.activity-details {
|
|
flex: 1;
|
|
}
|
|
|
|
.activity-title {
|
|
font-weight: 600;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.activity-company {
|
|
font-size: 0.9rem;
|
|
margin-bottom: 0.5rem;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.activity-meta {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.activity-status {
|
|
font-weight: 600;
|
|
|
|
&.application {
|
|
color: #3498db;
|
|
}
|
|
|
|
&.interview {
|
|
color: #9b59b6;
|
|
}
|
|
|
|
&.saved {
|
|
color: #f1c40f;
|
|
}
|
|
|
|
&.offer {
|
|
color: #2ecc71;
|
|
}
|
|
}
|
|
}
|
|
|
|
.events-card {
|
|
.events-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.event-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding-bottom: 1rem;
|
|
border-bottom: 1px solid var(--card-border, #eee);
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
padding-bottom: 0;
|
|
}
|
|
}
|
|
|
|
.event-date {
|
|
width: 3rem;
|
|
height: 3rem;
|
|
border-radius: 8px;
|
|
background-color: var(--primary-color);
|
|
color: white;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 1rem;
|
|
|
|
.event-day {
|
|
font-size: 1.2rem;
|
|
font-weight: 700;
|
|
line-height: 1;
|
|
}
|
|
|
|
.event-month {
|
|
font-size: 0.8rem;
|
|
text-transform: uppercase;
|
|
}
|
|
}
|
|
|
|
.event-details {
|
|
flex: 1;
|
|
}
|
|
|
|
.event-title {
|
|
font-weight: 600;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.event-company {
|
|
font-size: 0.9rem;
|
|
margin-bottom: 0.25rem;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.event-time {
|
|
font-size: 0.8rem;
|
|
opacity: 0.7;
|
|
}
|
|
}
|
|
|
|
.recommended-card {
|
|
.recommended-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.recommended-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding-bottom: 1rem;
|
|
border-bottom: 1px solid var(--card-border, #eee);
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
padding-bottom: 0;
|
|
}
|
|
}
|
|
|
|
.match-score {
|
|
background-color: rgba(46, 204, 113, 0.1);
|
|
color: #2ecc71;
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
padding: 0.25rem 0.5rem;
|
|
border-radius: 4px;
|
|
margin-right: 1rem;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.job-details {
|
|
flex: 1;
|
|
}
|
|
|
|
.job-title {
|
|
font-weight: 600;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.job-company {
|
|
font-size: 0.9rem;
|
|
margin-bottom: 0.25rem;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.job-meta {
|
|
display: flex;
|
|
gap: 1rem;
|
|
font-size: 0.8rem;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.view-job-btn {
|
|
background-color: transparent;
|
|
border: 1px solid var(--primary-color);
|
|
color: var(--primary-color);
|
|
padding: 0.4rem 0.75rem;
|
|
border-radius: 4px;
|
|
font-size: 0.8rem;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
|
|
&:hover {
|
|
background-color: var(--primary-color);
|
|
color: white;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|