Initial Commit
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="font-logo bg-gray-950 min-h-screen">
|
||||
<Suspense>
|
||||
<template #default>
|
||||
<div>
|
||||
<NavBar />
|
||||
<Hero />
|
||||
<Services />
|
||||
<About />
|
||||
<Skills />
|
||||
<Projects />
|
||||
<!-- <Testimonials /> -->
|
||||
<Contact />
|
||||
<Footer />
|
||||
<BackToTop />
|
||||
</div>
|
||||
</template>
|
||||
<template #fallback>
|
||||
<div class="flex justify-center items-center min-h-screen">
|
||||
<LoadingSpinner />
|
||||
</div>
|
||||
</template>
|
||||
</Suspense>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineAsyncComponent } from "vue";
|
||||
|
||||
const NavBar = defineAsyncComponent(() => import("@/components/Navbar.vue"));
|
||||
const Hero = defineAsyncComponent(() => import("@/components/Hero.vue"));
|
||||
const Services = defineAsyncComponent(() =>
|
||||
import("@/components/Services.vue")
|
||||
);
|
||||
const About = defineAsyncComponent(() => import("@/components/About.vue"));
|
||||
const Skills = defineAsyncComponent(() => import("@/components/Skills.vue"));
|
||||
const Projects = defineAsyncComponent(() =>
|
||||
import("@/components/Projects.vue")
|
||||
);
|
||||
// const Testimonials = defineAsyncComponent(() =>
|
||||
// import("@/components/Testemonial.vue")
|
||||
// );
|
||||
const Contact = defineAsyncComponent(() => import("@/components/Contact.vue"));
|
||||
const Footer = defineAsyncComponent(() => import("@/components/Footer.vue"));
|
||||
const BackToTop = defineAsyncComponent(() =>
|
||||
import("@/components/BackToTop.vue")
|
||||
);
|
||||
|
||||
import LoadingSpinner from "@/components/LoadingSpinner.vue";
|
||||
</script>
|
||||
|
||||
<style>
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #111827 #f1f1f1;
|
||||
}
|
||||
</style>
|
||||
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" zoomAndPan="magnify" viewBox="0 0 375 374.999991" height="500" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><clipPath id="dfb47b435a"><path d="M 82 90.4375 L 293.351562 90.4375 L 293.351562 284.6875 L 82 284.6875 Z M 82 90.4375 " clip-rule="nonzero"/></clipPath></defs><rect x="-37.5" width="450" fill="#ffffff" y="-37.499999" height="449.999989" fill-opacity="1"/><rect x="-37.5" width="450" fill="#000000" y="-37.499999" height="449.999989" fill-opacity="1"/><g clip-path="url(#dfb47b435a)"><path fill="#ffffff" d="M 256.140625 90.4375 C 256.230469 153.992188 256.226562 176.601562 256.226562 199.214844 C 256.226562 200.023438 256.0625 200.832031 255.910156 202.296875 C 255.910156 202.296875 255.90625 202.292969 255.90625 202.292969 L 236.234375 185.234375 C 219.777344 170.863281 203.328125 156.480469 186.835938 142.148438 C 186.53125 141.882812 186.152344 141.648438 185.75 141.460938 L 169.835938 127.660156 C 171.527344 127.496094 173.25 127.386719 175.007812 127.347656 C 182.699219 127.171875 190.394531 127.117188 240.265625 127.121094 L 240.265625 90.558594 C 190.644531 90.472656 183.191406 90.492188 175.746094 90.523438 C 154.546875 90.597656 135.253906 96.671875 118.527344 109.757812 C 95.390625 127.84375 82.710938 151.675781 82.285156 181.164062 C 81.890625 208.75 82.082031 236.34375 82.128906 284.558594 L 119.011719 284.558594 C 119.011719 253.054688 119.011719 240.308594 119.011719 227.570312 C 119.011719 224.382812 119.027344 224.378906 122.160156 224.378906 C 148.136719 224.378906 174.117188 224.378906 200.09375 224.378906 C 200.898438 224.378906 201.707031 224.378906 202.507812 224.378906 C 202.675781 224.101562 202.839844 223.820312 203.007812 223.542969 C 202.375 223.125 201.6875 222.773438 201.121094 222.28125 C 188.414062 211.238281 175.710938 200.195312 163.042969 189.109375 C 161.785156 188.007812 160.496094 187.574219 158.824219 187.582031 C 146.578125 187.636719 134.335938 187.613281 122.085938 187.605469 C 119.101562 187.605469 119.039062 187.601562 118.988281 184.527344 C 118.835938 175.164062 120.652344 166.214844 125.175781 157.96875 C 127.730469 153.316406 130.617188 149.183594 133.832031 145.570312 L 176.632812 182.691406 C 196.023438 199.566406 215.417969 216.445312 234.789062 233.335938 C 253.65625 249.785156 272.492188 266.277344 291.34375 282.738281 C 291.730469 283.078125 292.203125 283.3125 293.0625 283.875 C 293.0625 282.738281 293.0625 282.0625 293.0625 281.382812 C 293.0625 231.375 293.066406 181.375 293.066406 90.425781 L 256.140625 90.425781 Z M 256.140625 90.4375 " fill-opacity="1" fill-rule="nonzero"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 161 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<section class="text-white mt-18" id="about">
|
||||
<div class="absolute z-0 top-[93rem] inset-x-0 h-64 flex items-start">
|
||||
<div
|
||||
class="h-24 w-64 bg-gradient-to-br from-primary via-secondary blur-2xl to-[#570cac] opacity-20"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
class="md:grid md:grid-cols-2 gap-8 items-center py-8 px-4 xl:gap-16 sm:py-16 xl:px-16 z-1"
|
||||
>
|
||||
<div data-aos="flip-right">
|
||||
<h2 class="text-4xl font-bold text-white text-left mb-8">
|
||||
My Education
|
||||
</h2>
|
||||
<div class="space-y-8 py-8">
|
||||
<div
|
||||
v-for="el in education"
|
||||
:key="el.id"
|
||||
class="flex items-center md:w-[80%] w-full rounded-xl bg-gray-900 shadow-lg border border-[#1f1641]"
|
||||
>
|
||||
<div class="w-1/4 items-center justify-center flex">
|
||||
<img
|
||||
src="https://img.icons8.com/ios-glyphs/60/ffffff/graduation-cap--v1.png"
|
||||
alt="graduation-cap--v1"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-3/4 pl-4 py-2">
|
||||
<h3
|
||||
class="text-2xl font-semibold uppercase text-transparent bg-clip-text bg-gradient-to-r from-primary to-secondary lg:text-xl"
|
||||
>
|
||||
{{ el.institution }}
|
||||
</h3>
|
||||
<p class="text-white">{{ el.course }}</p>
|
||||
<p class="text-gray-400">{{ el.year }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-4 md:mt-0 text-left flex flex-col z-10 h-full"
|
||||
data-aos="flip-right"
|
||||
>
|
||||
<h2 class="text-4xl font-bold text-white md:text-center text-left mb-4">
|
||||
More
|
||||
<span
|
||||
class="text-transparent bg-clip-text bg-gradient-to-r from-primary to-secondary"
|
||||
>About</span
|
||||
>
|
||||
Me
|
||||
</h2>
|
||||
<p class="text-base lg:text-lg mt-8 py-8 text-justify">
|
||||
I am a Software Engineering student from Portugal with 4+ years of
|
||||
experience from my internships and Self Learning + Personal Projects.
|
||||
I am passionate about technology and always eager to learn more. I am
|
||||
currently pursuing my Bachelor's on Software Engineering after having
|
||||
completed a CTeSP in programming, where I gained a solid foundation in
|
||||
C, .NET, PHP, Java, and MySQL. In my free time I've taken a few online
|
||||
courses on Unity 3D, Swift/SwiftUI, Cypress, Git, React, Golang. I've
|
||||
also had the pleasure to be a QA/QC Intern at VOID Software in Leiria
|
||||
for five months. There, I contributed to the testing and quality
|
||||
assurance of several projects, using Cypress and Cucumber to automate
|
||||
and streamline the testing process and Git to manage the source code
|
||||
and collaborate with the development team. I am always looking for new
|
||||
challenges and opportunities to grow as a developer.
|
||||
</p>
|
||||
<div class="grid grid-cols-3 gap-4 max-w-lg pt-8">
|
||||
<div
|
||||
class="text-center rounded-xl bg-gray-900 shadow-lg border border-[#1f1641] p-3"
|
||||
>
|
||||
<h3 class="text-white font-bold text-xl sm:text-2xl lg:text-3xl">
|
||||
+200
|
||||
</h3>
|
||||
<p class="text-sm sm:text-base text-gray-300">Happy Clients</p>
|
||||
</div>
|
||||
<div
|
||||
class="text-center rounded-xl bg-gray-900 shadow-lg border border-[#1f1641] p-3"
|
||||
>
|
||||
<h3 class="text-white font-bold text-xl sm:text-2xl lg:text-3xl">
|
||||
+4
|
||||
</h3>
|
||||
<p class="text-sm sm:text-base text-gray-300">Years Experience</p>
|
||||
</div>
|
||||
<div
|
||||
class="text-center rounded-xl bg-gray-900 shadow-lg border border-[#1f1641] p-3"
|
||||
>
|
||||
<h3 class="text-white font-bold text-xl sm:text-2xl lg:text-3xl">
|
||||
+300
|
||||
</h3>
|
||||
<p class="text-sm sm:text-base text-gray-300">Projects</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const education = ref([
|
||||
{
|
||||
id: 1,
|
||||
course: "CTeSP in Programing and IT",
|
||||
institution: "Polytechnic of Leiria",
|
||||
year: "2023",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
course: "Bachelor's Degree in Software Engineering",
|
||||
institution: "Polytechnic of Leiria",
|
||||
year: "2026 (Expected)",
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<button
|
||||
v-if="isVisible"
|
||||
@click="scrollToTop"
|
||||
class="fixed bottom-4 right-4 bg-gradient-to-r from-primary to-pink-500 text-white rounded-full w-12 h-12 flex items-center justify-center text-xl cursor-pointer transition-opacity duration-300 hover:bg-blue-600"
|
||||
>
|
||||
↑
|
||||
</button>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
|
||||
const isVisible = ref(false);
|
||||
|
||||
const handleScroll = () => {
|
||||
isVisible.value = window.scrollY > 300;
|
||||
};
|
||||
|
||||
const scrollToTop = () => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: "smooth",
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<section class="text-white mt-20" id="contact">
|
||||
<h2 class="text-4xl font-bold text-white text-left mb-4 px-4 xl:pl-16">
|
||||
Let's Connect
|
||||
</h2>
|
||||
<div
|
||||
class="grid md:grid-cols-2 gap-4 relative px-4 xl:px-16 mt-8"
|
||||
data-aos="zoom-in-up"
|
||||
>
|
||||
<div>
|
||||
<p class="text-[#ADB7BE]">
|
||||
Check my email and linkedin or send a message here to get in touch!
|
||||
</p>
|
||||
<div class="col-lg-4 col-md-4 mb-lg-0 mt-5">
|
||||
<div class="flex mb-10 items-center">
|
||||
<div
|
||||
class="p-2"
|
||||
style="
|
||||
background: #111a3e;
|
||||
width: 50px;
|
||||
height: 46px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 1px solid #111a3e;
|
||||
backdrop-filter: blur(9px);
|
||||
-webkit-backdrop-filter: blur(9px);
|
||||
"
|
||||
>
|
||||
<img
|
||||
src="https://img.icons8.com/metro/50/ffffff/new-post.png"
|
||||
alt="new-post"
|
||||
class="w-6"
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-5 text-white">
|
||||
<h4>Email</h4>
|
||||
<p class="text-[#ADB7BE]">info@fernandovideira.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mb-10 items-center">
|
||||
<div
|
||||
class="p-2"
|
||||
style="
|
||||
background: #111a3e;
|
||||
width: 50px;
|
||||
height: 46px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 1px solid #111a3e;
|
||||
backdrop-filter: blur(9px);
|
||||
-webkit-backdrop-filter: blur(9px);
|
||||
"
|
||||
>
|
||||
<img
|
||||
src="https://img.icons8.com/ios-filled/50/ffffff/phone.png"
|
||||
alt="new-post"
|
||||
class="w-6"
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-5 text-white">
|
||||
<h4>Phone</h4>
|
||||
<p class="text-[#ADB7BE]">(+351) 923-543-517</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mb-10 items-center">
|
||||
<div
|
||||
class="p-2"
|
||||
style="
|
||||
background: #111a3e;
|
||||
width: 50px;
|
||||
height: 46px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 1px solid #111a3e;
|
||||
backdrop-filter: blur(9px);
|
||||
-webkit-backdrop-filter: blur(9px);
|
||||
"
|
||||
>
|
||||
<img
|
||||
src="https://img.icons8.com/ios-filled/50/ffffff/linkedin.png"
|
||||
alt="new-post"
|
||||
class="w-6"
|
||||
/>
|
||||
</div>
|
||||
<div class="ml-5 text-white">
|
||||
<h4>Linkedin</h4>
|
||||
<a href="https://www.linkedin.com/in/fernando-videira-info/"
|
||||
><p class="text-[#ADB7BE]">Fernando Videira</p></a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="p-6"
|
||||
style="
|
||||
background: #101828;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #111a3e;
|
||||
backdrop-filter: blur(9px);
|
||||
-webkit-backdrop-filter: blur(9px);
|
||||
"
|
||||
>
|
||||
<form
|
||||
ref="form"
|
||||
class="flex flex-col p-2"
|
||||
data-aos="zoom-in-up"
|
||||
@submit.prevent="sendEmail"
|
||||
>
|
||||
<div class="mb-6">
|
||||
<label for="email" class="text-white block mb-2 text-sm font-medium"
|
||||
>Email</label
|
||||
>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
class="bg-gray-950 placeholder:[#9CA2A9] text-gray-100 text-sm rounded-lg block w-full p-2.5"
|
||||
placeholder="[email protected]"
|
||||
name="email"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<label
|
||||
for="subject"
|
||||
class="text-white block mb-2 text-sm font-medium"
|
||||
>Subject</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="subject"
|
||||
class="bg-gray-950 placeholder:[#9CA2A9] text-gray-100 text-sm rounded-lg block w-full p-2.5"
|
||||
placeholder="Subject"
|
||||
name="subject"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<label
|
||||
for="message"
|
||||
class="text-white block mb-2 text-sm font-medium"
|
||||
>Message</label
|
||||
>
|
||||
<textarea
|
||||
id="message"
|
||||
rows="4"
|
||||
class="bg-gray-950 placeholder:[#9CA2A9] text-gray-100 text-sm rounded-lg block w-full p-2.5"
|
||||
placeholder="Message"
|
||||
name="message"
|
||||
></textarea>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="z-1 w-[100%!important] px-6 md:px-7 py-3 rounded-full sm:w-max flex justify-center text-white bg-primary border-2 border-transparent"
|
||||
>
|
||||
Send Message
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="bg-gradient-to-tr opacity-25 from-[#570cac] to-primary blur-2xl h-20 w-80 z-0 absolute -top-1/2 -left-4 transform -translate-x-2/3 -translate-1/2"
|
||||
></div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import emailjs from "emailjs-com";
|
||||
import { useToast } from "vue-toast-notification";
|
||||
|
||||
const $toast = useToast();
|
||||
const form = ref(null);
|
||||
|
||||
const sendEmail = async () => {
|
||||
const isEmpty = [...form.value.elements].some(
|
||||
(el) => el.tagName !== "BUTTON" && el.type !== "submit" && !el.value.trim()
|
||||
);
|
||||
if (isEmpty) {
|
||||
$toast.warning("Please fill in all fields");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await emailjs.sendForm(
|
||||
"service_0oh6s0e",
|
||||
"template_4s8pg7r",
|
||||
form.value,
|
||||
"fSghIDn2dawqKYyH7"
|
||||
);
|
||||
$toast.success("Email sent successfully!");
|
||||
form.value.reset();
|
||||
} catch (err) {
|
||||
$toast.error("Error sending email. Try again later.");
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<footer
|
||||
class="mt-8 border z-10 border-[#33353F] border-l-transparent border-r-transparent text-white"
|
||||
>
|
||||
<div class="container p-12 flex justify-between">
|
||||
<div>
|
||||
<img src="@/assets/logo.png" alt="Logo" width="40" height="40" />
|
||||
</div>
|
||||
<p class="text-slate-600">© All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<section class="relative w-full" data-aos="zoom-in-up">
|
||||
<div class="absolute top-0 inset-x-0 h-64 flex items-start">
|
||||
<div
|
||||
class="h-24 w-2/3 bg-gradient-to-br from-[#570cac] blur-2xl invisible opacity-40"
|
||||
></div>
|
||||
<div
|
||||
class="h-20 w-3/5 bg-gradient-to-r from-[#670ccf] opacity-40 blur-2xl"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
class="w-full px-5 sm:px-8 md:px-12 max-w-screen-lg lg:max-w-screen-xl mx-auto relative"
|
||||
>
|
||||
<div
|
||||
class="grid lg:grid-cols-2 gap-10 xl:gap-14 relative pt-24 lg:max-w-none max-w-2xl md:max-w-3xl mx-auto"
|
||||
>
|
||||
<div class="lg:py-6">
|
||||
<div class="text-center lg:text-left">
|
||||
<h1
|
||||
class="pt-4 text-white font-bold text-4xl md:text-5xl lg:text-6xl"
|
||||
>
|
||||
Hi, I'm
|
||||
<span
|
||||
class="text-transparent bg-clip-text bg-gradient-to-r from-primary to-pink-500"
|
||||
>Fernando</span
|
||||
>🧑🏻💻
|
||||
</h1>
|
||||
</div>
|
||||
<p
|
||||
class="text-gray-300 pt-8 text-center lg:text-left mx-auto max-w-xl"
|
||||
>
|
||||
I'm a passionate Software Engineering student and Entrepreneur
|
||||
always looking for new challenges!
|
||||
</p>
|
||||
<div
|
||||
class="flex items-center gap-3 pt-9 flex-col sm:flex-row sm:w-max sm:mx-auto lg:mx-0"
|
||||
>
|
||||
<button
|
||||
class="px-6 md:px-7 py-3 rounded-full relative group w-full sm:w-max flex justify-center"
|
||||
>
|
||||
<a href="#contact" class="absolute z-1 inset-0 rounded-3xl"></a>
|
||||
<span
|
||||
class="absolute inset-0 rounded-3xl group-hover:scale-105 origin-center transition-all ease-in-out bg-primary border-2 border-transparent"
|
||||
></span>
|
||||
<span class="relative flex items-center justify-center text-white"
|
||||
>Hire Me</span
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
class="border border-primary px-6 md:px-7 py-3 rounded-full relative group w-full sm:w-max flex justify-center"
|
||||
>
|
||||
<div
|
||||
class="hover:scale-105 transition-all ease-in-out flex justify-center items-center relative"
|
||||
>
|
||||
<div class="svg-container">
|
||||
<svg
|
||||
class="download-icon"
|
||||
width="18"
|
||||
height="22"
|
||||
viewBox="0 0 18 22"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
class="download-arrow"
|
||||
d="M13 9L9 13M9 13L5 9M9 13V1"
|
||||
stroke="#f59e0b"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M1 17V18C1 18.7956 1.31607 19.5587 1.87868 20.1213C2.44129 20.6839 3.20435 21 4 21H14C14.7956 21 15.5587 20.6839 16.1213 20.1213C16.6839 19.5587 17 18.7956 17 18V17"
|
||||
stroke="#f59e0b"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
<div class="download-loader text-white hidden2"></div>
|
||||
</div>
|
||||
<a
|
||||
href="/resume.pdf"
|
||||
download="resume.pdf"
|
||||
class="pl-2 text-primary"
|
||||
>Download Resume</a
|
||||
>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lg:h-full md:flex">
|
||||
<div
|
||||
class="flex w-full h-96 min-h-[24rem] lg:min-h-[none] lg:w-full lg:h-full items-center relative"
|
||||
>
|
||||
<div
|
||||
class="absolute z-0 top-1/2 -translate-y-1/2 w-5/6 right-0 h-[calc(80%+20px)] bg-gradient-to-tr opacity-25 from-[#570cac] to-primary blur-2xl"
|
||||
></div>
|
||||
<div
|
||||
class="absolute h-full z-10 p-2 -translate-y-1/2 top-1/2 lg:right-3 md:right-40 sm:right-16 rounded-full shadow-lg border border-primary"
|
||||
>
|
||||
<img
|
||||
src="@/assets/profile_image.jpg"
|
||||
alt="hero picture"
|
||||
width="500"
|
||||
height="auto"
|
||||
loading="lazy"
|
||||
class="w-full h-full rounded-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import AOS from "aos";
|
||||
import "aos/dist/aos.css";
|
||||
|
||||
AOS.init();
|
||||
</script>
|
||||
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div class="flex justify-center items-center h-full">
|
||||
<svg
|
||||
class="animate-spin h-16 w-16 text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color: #f59e0b" />
|
||||
<stop offset="100%" style="stop-color: #ec4899" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<circle
|
||||
class="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="url(#gradient1)"
|
||||
stroke-width="4"
|
||||
fill="none"
|
||||
></circle>
|
||||
<path
|
||||
fill="#f59e0b"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
<script setup></script>
|
||||
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<header
|
||||
class="flex justify-between items-center p-6 bg-opacity-50 relative z-20"
|
||||
>
|
||||
<div class="text-white text-3xl font-bold">
|
||||
<div class="flex flex-row items-center">
|
||||
<img src="@/assets/logo.png" alt="Logo" width="60" height="60" />
|
||||
<h1>Portfolio</h1>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Mobile Toggle Button -->
|
||||
<div class="md:hidden z-30">
|
||||
<button
|
||||
type="button"
|
||||
class="block focus:outline-none"
|
||||
@click="isMenuOpen = !isMenuOpen"
|
||||
>
|
||||
<span v-if="isMenuOpen" class="text-5xl">
|
||||
<img
|
||||
src="https://img.icons8.com/ios-filled/100/ffffff/delete-sign.png"
|
||||
alt="close"
|
||||
width="50"
|
||||
height="50"
|
||||
/>
|
||||
</span>
|
||||
<span v-else class="text-5xl">
|
||||
<img
|
||||
src="https://img.icons8.com/ios-filled/100/ffffff/menu--v6.png"
|
||||
alt="menu"
|
||||
width="50"
|
||||
height="50"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Navbar Links -->
|
||||
<nav
|
||||
:class="[
|
||||
'fixed inset-0 z-20 flex flex-col items-center justify-center bg-[#111827] md:relative md:bg-transparent md:flex md:justify-between md:flex-row',
|
||||
isMenuOpen ? 'block' : 'hidden',
|
||||
]"
|
||||
>
|
||||
<ul
|
||||
class="flex flex-col items-center space-y-5 md:flex-row md:space-x-5 md:space-y-0"
|
||||
>
|
||||
<li v-for="item in Menu" :key="item.name">
|
||||
<a
|
||||
:href="item.href"
|
||||
class="block text-white hover:text-primary ease-linear text-2xl md:text-lg"
|
||||
@click2="scrollToSection(item.href)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const Menu = ref([
|
||||
{ name: "Services", href: "#services" },
|
||||
{ name: "About Me", href: "#about" },
|
||||
{ name: "Skills", href: "#skills" },
|
||||
{ name: "Projects", href: "#projects" },
|
||||
// { name: "Testimonials", href: "#testimonials" },
|
||||
{ name: "Contact", href: "#contact" },
|
||||
]);
|
||||
|
||||
const isMenuOpen = ref(false);
|
||||
const scrollToSection = (href) => {
|
||||
isMenuOpen.value = false;
|
||||
const section = document.querySelector(href);
|
||||
if (section) {
|
||||
section.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,277 @@
|
||||
<template>
|
||||
<section class="text-white mt-20" id="projects">
|
||||
<div class="px-4 xl:pl-16">
|
||||
<div class="mb-4 md:flex md:justify-between xl:pr-16">
|
||||
<h2 class="text-4xl font-bold text-white">My Projects</h2>
|
||||
<div class="flex space-x-4 mb-4 mt-5 md:mt-0">
|
||||
<button
|
||||
class="hover:text-primary z-10"
|
||||
v-for="cat in ['All', 'Academic', 'Personal']"
|
||||
:key="cat"
|
||||
@click="() => (selectedCategory = cat)"
|
||||
>
|
||||
{{ cat }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
class="px-4 sm:py-16 xl:pr-16 grid grid-cols-1 gap-6 pt-10 sm:grid-cols-2 md:gap-10 md:pt-12 lg:grid-cols-3"
|
||||
data-aos="fade-right"
|
||||
>
|
||||
<div v-for="p in filteredProjects" :key="p.id">
|
||||
<div
|
||||
class="h-52 md:h-[24rem] rounded-t-xl relative group"
|
||||
:style="{
|
||||
backgroundImage: 'url(' + p.image + ')',
|
||||
backgroundSize: 'cover',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="overlay items-center justify-center absolute top-0 left-0 w-full h-full bg-[#181818] bg-opacity-0 hidden group-hover:flex group-hover:bg-opacity-80 transition-all duration-50"
|
||||
>
|
||||
<a
|
||||
v-if="p.webURL"
|
||||
:href="p.webURL"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="h-14 w-14 mr-2 border-2 relative rounded-full border-[#ADB7BE] hover:border-white group/link"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
data-slot="icon"
|
||||
class="h-10 w-10 text-[#ADB7BE] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 cursor-pointer group-hover/link:text-white"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"
|
||||
></path>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
<span
|
||||
v-else
|
||||
class="h-14 w-14 mr-2 border-2 relative rounded-full border-gray-600 opacity-40 cursor-not-allowed flex items-center justify-center"
|
||||
aria-disabled="true"
|
||||
title="Live demo unavailable"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
data-slot="icon"
|
||||
class="h-10 w-10 text-[#ADB7BE] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 cursor-pointer group-hover/link:text-white"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"
|
||||
></path>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<a
|
||||
v-if="p.gitURL"
|
||||
:href="p.gitURL"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="h-14 w-14 mr-2 border-2 relative rounded-full border-[#ADB7BE] hover:border-white group/link"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
aria-hidden="true"
|
||||
data-slot="icon"
|
||||
class="h-10 w-10 text-[#ADB7BE] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 cursor-pointer"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M17.25 6.75 22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3-4.5 16.5"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
<span
|
||||
v-else
|
||||
class="h-14 w-14 mr-2 border-2 relative rounded-full border-gray-600 opacity-40 cursor-not-allowed flex items-center justify-center"
|
||||
aria-disabled="true"
|
||||
title="Live demo unavailable"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
aria-hidden="true"
|
||||
data-slot="icon"
|
||||
class="h-10 w-10 text-[#ADB7BE] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 cursor-pointer"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M17.25 6.75 22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3-4.5 16.5"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-white rounded-b-xl mt-3 bg-gray-900 shadow-lg border border-[#1f1641] py-6 px-4"
|
||||
>
|
||||
<h3 class="text-lg font-semibold uppercase lg:text-xl">
|
||||
{{ p.title }}
|
||||
</h3>
|
||||
<p class="text-[#ADB7BE]">{{ p.description }}</p>
|
||||
<div class="flex flex-wrap p-2.5">
|
||||
<div
|
||||
v-for="tech in p.technologies"
|
||||
:key="tech"
|
||||
class="text-center ml-1 mt-1 rounded-3xl bg-gray-800"
|
||||
style="
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #111827;
|
||||
backdrop-filter: blur(9px);
|
||||
-webkit-backdrop-filter: blur(9px);
|
||||
"
|
||||
>
|
||||
<p class="px-5 py-2">{{ tech }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, computed } from "vue";
|
||||
|
||||
const projects = ref([
|
||||
{
|
||||
id: 1,
|
||||
category: "Academic",
|
||||
image: "src/assets/test.jpg",
|
||||
title: "Stuff&Go Web Store",
|
||||
description: "Supermarket e-commerce platform",
|
||||
technologies: ["PHP", "JavaScript", "MySQL"],
|
||||
gitURL: "https://github.com/FernandoJVideira/PL2-G7_ProjetoPlatSI",
|
||||
webURL: "",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
category: "Academic",
|
||||
image: "src/assets/test.jpg",
|
||||
title: "Stuff&Go Mobile App",
|
||||
description: "Mobile application for supermarket shopping.",
|
||||
technologies: ["Java", "MQTT", "Android"],
|
||||
gitURL: "https://github.com/FernandoJVideira/PL2-G7_ProjetoAMSI",
|
||||
webURL: "",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
category: "Academic",
|
||||
image: "src/assets/RestGest.png",
|
||||
title: "RestGest",
|
||||
description: "Restaurant POS system.",
|
||||
technologies: ["C#", ".Net", "SQL Server"],
|
||||
gitURL: "https://github.com/FernandoJVideira/PSI_DA_PL2_G",
|
||||
webURL: "",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
category: "Academic",
|
||||
image: "src/assets/test.jpg",
|
||||
title: "La Redoute Product Page UI",
|
||||
description: "UI design for a La Redoute product page.",
|
||||
technologies: ["HTML", "Bootstrap", "Three.js"],
|
||||
gitURL: "https://github.com/FernandoJVideira/SGI_Projeto24",
|
||||
webURL: "",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
category: "Academic",
|
||||
image: "src/assets/chat.png",
|
||||
title: "Secure Chat",
|
||||
description: "End-to-End Encrypted Multi-Client Chat Application.",
|
||||
technologies: ["C#", ".Net", "Encryption Algorithms"],
|
||||
gitURL: "https://github.com/FernandoJVideira/SGI_Projeto24",
|
||||
webURL: "",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
category: "Personal",
|
||||
image: "src/assets/velox_bot.png",
|
||||
title: "Velox Discord Bot",
|
||||
description: "Multi-purpose Discord bot built in Python.",
|
||||
technologies: ["Python", "PostgreSQL", "Discord.py"],
|
||||
gitURL: "https://github.com/FernandoJVideira/VeloxDiscordBot",
|
||||
webURL: "",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
category: "Personal",
|
||||
image: "src/assets/velox_web.png",
|
||||
title: "Velox Web Framework",
|
||||
description: "Fullstack laravel like web framework built with Go.",
|
||||
technologies: ["Go"],
|
||||
gitURL: "https://github.com/FernandoJVideira/velox",
|
||||
webURL: "",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
category: "Personal",
|
||||
image: "src/assets/profile_image.jpg",
|
||||
title: "My Portfolio",
|
||||
description: "Showcase of my projects and skills built in Vue 3.",
|
||||
technologies: ["Vue.js", "Tailwind CSS"],
|
||||
gitURL: "",
|
||||
webURL: "https://fernandovideira.com",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
category: "Personal",
|
||||
image: "src/assets/Lk.jpg",
|
||||
title: "LK Results Website",
|
||||
description: "Landing Page for my Company.",
|
||||
technologies: ["React.js", "Typescript"],
|
||||
gitURL: "",
|
||||
webURL: "https://lk-results.com",
|
||||
},
|
||||
]);
|
||||
|
||||
const selectedCategory = ref("All");
|
||||
|
||||
const filteredProjects = computed(() => {
|
||||
if (selectedCategory.value === "All") {
|
||||
return projects.value;
|
||||
}
|
||||
return projects.value.filter(
|
||||
(p) =>
|
||||
p.category.toLocaleLowerCase() ===
|
||||
selectedCategory.value.toLocaleLowerCase()
|
||||
);
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<section class="text-white mt-20" id="services">
|
||||
<div class="px-4 xl:pl-16">
|
||||
<h2 class="text-4xl font-bold text-white mb-4">My Services</h2>
|
||||
</div>
|
||||
<div
|
||||
class="py-8 xl:px-16 px-4 sm:py-16 grid grid-cols-1 gap-6 pt-10 sm:grid-cols-2 md:gap-10 md:pt-12 lg:grid-cols-3"
|
||||
>
|
||||
<div
|
||||
v-for="service in services"
|
||||
:key="service.id"
|
||||
data-aos="fade-up"
|
||||
class="px-8 py-12 rounded-xl bg-gray-900 shadow-lg border border-[#1f1641]"
|
||||
>
|
||||
<div class="mx-auto h-24 w-24 text-center xl:h-28 xl:w-28">
|
||||
<div>
|
||||
<img :src="service.icon" alt="service icon" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<h3
|
||||
class="pt-8 text-lg font-semibold uppercase text-transparent bg-clip-text bg-gradient-to-r from-primary to-secondary lg:text-xl"
|
||||
>
|
||||
{{ service.name }}
|
||||
</h3>
|
||||
<p class="text-gray pt-4 text-sm group-hover:text-white md:text-base">
|
||||
{{ service.description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const services = ref([
|
||||
{
|
||||
id: 1,
|
||||
icon: "https://img.icons8.com/ios-filled/100/ffffff/google-code.png",
|
||||
name: "Frontend Development",
|
||||
description: "Building responsive and modern web applications.",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
icon: "https://img.icons8.com/external-vectorslab-glyph-vectorslab/1000/fffeee/external-Technical-Writing-mobile-app-development-vectorslab-glyph-vectorslab.png",
|
||||
name: "Backend Development",
|
||||
description: "Building robust and scalable server-side RESTful APIs.",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
icon: "https://img.icons8.com/ios-filled/100/ffffff/developer-mode.png",
|
||||
name: "Mobile Development",
|
||||
description:
|
||||
"Building mobile applications with a focus on user experience and performance.",
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<section class="text-white mt-18" id="skills">
|
||||
<div class="absolute right-0 top-[110rem] h-full w-full justify-end">
|
||||
<span class="flex opacity-20">
|
||||
<span class="w-16 h-32 rounded-l-full flex bg-primary blur-2xl"></span>
|
||||
<span
|
||||
class="w-16 h-32 rounded-l-full flex bg-[#f88fc2] blur-2xl mt-14"
|
||||
></span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="md:grid md:grid-cols-2 gap-8 items-center py-8 px-4 xl:gap-16 xl:px-16"
|
||||
>
|
||||
<div class="mt-4 md:mt-0 text-left flex flex-col z-10 h-full w-[80%]">
|
||||
<h2 class="text-4xl font-bold text-white text-left mb-4">
|
||||
My
|
||||
<span
|
||||
class="text-transparent bg-clip-text bg-gradient-to-r from-primary to-secondary"
|
||||
>
|
||||
Skills
|
||||
</span>
|
||||
</h2>
|
||||
<div class="mt-8" v-for="skill in skills">
|
||||
<div class="flex items-end justify-between" data-aos="fade-right">
|
||||
<h4 class="font-semibold uppercase text-white">{{ skill.name }}</h4>
|
||||
<h3 class="text-2xl font-bold text-white">{{ skill.width }}</h3>
|
||||
</div>
|
||||
<div class="mt-2 h-1 w-full bg-[#131d30] rounded-full">
|
||||
<div
|
||||
class="h-1 rounded-full bg-primary"
|
||||
:style="{ width: skill.width }"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-aos="flip-left">
|
||||
<h2
|
||||
class="text-4xl font-bold text-white text-left mb-8 md:text-center md:mt-0 mt-8"
|
||||
>
|
||||
My Experiences
|
||||
</h2>
|
||||
<div class="space-y-8 py-8" data-aos="fade-left">
|
||||
<div
|
||||
v-for="exp in experiences"
|
||||
:key="exp.id"
|
||||
class="flex items-center rounded-xl p-4 bg-gray-900 shadow-lg border border-[#1f1641]"
|
||||
>
|
||||
<div class="w-1/4 items-center justify-center flex">
|
||||
<img
|
||||
src="https://img.icons8.com/ios-filled/100/ffffff/lawyer.png"
|
||||
alt="lawyer"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-3/4 pl-4">
|
||||
<h3
|
||||
class="text-2xl font-semibold uppercase text-transparent bg-clip-text bg-gradient-to-r from-primary to-secondary"
|
||||
>
|
||||
{{ exp.role }}
|
||||
</h3>
|
||||
<p class="text-white">{{ exp.company }}</p>
|
||||
<p class="text-gray-400">{{ exp.date }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const skills = ref([
|
||||
{
|
||||
id: 1,
|
||||
name: "Go",
|
||||
width: "90% ",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "C#",
|
||||
width: "70%",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Nuxt.js",
|
||||
width: "55%",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Python",
|
||||
width: "45%",
|
||||
},
|
||||
]);
|
||||
|
||||
const experiences = ref([
|
||||
{
|
||||
id: 1,
|
||||
role: "QA Engineer Intern",
|
||||
company: "Void Software",
|
||||
date: "Feb 2023 - Jul 2023",
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<section class="text-white mt-20" id="testimonials" data-aos="zoom-in">
|
||||
<h2 class="text-4xl font-bold text-white text-left mb-4 px-4 xl:pl-16">
|
||||
Testimonials
|
||||
</h2>
|
||||
<div class="px-4 xl:px-16">
|
||||
<Carousel v-bind="settings" :breakpoints="breakpoints">
|
||||
<Slide v-for="t in testimonials" :key="t.id">
|
||||
<div class="carousel__item p-4">
|
||||
<div
|
||||
class="w-full mx-auto bg-gray-900 shadow-lg border border-[#1f1641] p-5 text-white font-light mb-6"
|
||||
>
|
||||
<div class="w-full flex mb-4 items-center">
|
||||
<div
|
||||
class="overflow-hidden rounded-full w-10 h-10 bg-gray-50 border border-gray-200"
|
||||
>
|
||||
<img :src="t.image" alt="Profile Image" loading="lazy" />
|
||||
</div>
|
||||
<h6 class="ml-4 font-bold text-sm uppercase text-white">
|
||||
{{ t.fullName }}
|
||||
</h6>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<p class="text-sm leading-tight">
|
||||
<span
|
||||
class="text-lg leading-none italic font-bold text-white mr-1"
|
||||
>"</span
|
||||
>{{ t.comment
|
||||
}}<span
|
||||
class="text-lg leading-none italic font-bold text-white mr-1"
|
||||
>"</span
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Slide>
|
||||
<template #addons>
|
||||
<Navigation />
|
||||
</template>
|
||||
</Carousel>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { Carousel, Navigation, Slide } from "vue3-carousel";
|
||||
import "vue3-carousel/dist/carousel.css";
|
||||
|
||||
const settings = ref({
|
||||
itemsToShow: 1,
|
||||
snapAlign: "center",
|
||||
});
|
||||
|
||||
const breakpoints = ref({
|
||||
700: {
|
||||
itemsToShow: 2.5,
|
||||
snapAlign: "center",
|
||||
},
|
||||
1024: {
|
||||
itemsToShow: 3,
|
||||
snapAlign: "start",
|
||||
},
|
||||
});
|
||||
|
||||
const testimonials = ref([
|
||||
{
|
||||
id: 1,
|
||||
fullName: "client 1",
|
||||
image: "src/assets/profile_image.jpg",
|
||||
comment:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Aperiam minima reprehenderit maiores itaque molestiae optio, voluptatibus iusto eos doloremque consectetur! ",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
fullName: "client 2",
|
||||
image: "src/assets/profile_image.jpg",
|
||||
comment:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Aperiam minima reprehenderit maiores itaque molestiae optio, voluptatibus iusto eos doloremque consectetur! ",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
fullName: "client 3",
|
||||
image: "src/assets/profile_image.jpg",
|
||||
comment:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Aperiam minima reprehenderit maiores itaque molestiae optio, voluptatibus iusto eos doloremque consectetur! ",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
fullName: "client 4",
|
||||
image: "src/assets/profile_image.jpg",
|
||||
comment:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Aperiam minima reprehenderit maiores itaque molestiae optio, voluptatibus iusto eos doloremque consectetur! ",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
fullName: "client 5",
|
||||
image: "src/assets/profile_image.jpg",
|
||||
comment:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Aperiam minima reprehenderit maiores itaque molestiae optio, voluptatibus iusto eos doloremque consectetur! ",
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.carousel__prev,
|
||||
.carousel__next {
|
||||
color: white !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,10 @@
|
||||
import { createApp } from "vue";
|
||||
import "./style.css";
|
||||
import App from "./App.vue";
|
||||
|
||||
import ToastPlugin from "vue-toast-notification";
|
||||
// Import one of the available themes
|
||||
//import 'vue-toast-notification/dist/theme-default.css';
|
||||
import "vue-toast-notification/dist/theme-bootstrap.css";
|
||||
|
||||
createApp(App).use(ToastPlugin).mount("#app");
|
||||
@@ -0,0 +1,7 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
--color-primary: #f59e0b;
|
||||
--color-secondary: #ec4899;
|
||||
--font-logo: "Outfit", sans-serif;
|
||||
}
|
||||