mirror of
https://github.com/mmahdium/portfolio.git
synced 2026-08-17 05:24:30 +03:30
feat(portfolio): add resume navigation and improve layout handling
- Add "View Resume" button to Hero component with responsive design (desktop/mobile variants) - Implement gradient styling with hover animations and pulse effect on desktop button - Wrap Hero content in flex container for proper button alignment - Remove client:only directive from TopNav component in default layout - Add semantic <main> tag wrapper around slot content in default layout - Implement layoutKey computed property to force re-render on route changes - Add scrollToTop meta and onMounted scroll reset to resume page - Add "Back to Home" navigation button to resume page with print-safe styling - Improve resume page background with white/dark mode support - Add print media query to hide navigation elements during printing - Enhance user navigation flow between home and resume pages
This commit is contained in:
@@ -15,18 +15,42 @@
|
|||||||
<UIcon name="i-twemoji-round-pushpin" class="text-base text-primary-600 me-1 dark:text-primary-300" />
|
<UIcon name="i-twemoji-round-pushpin" class="text-base text-primary-600 me-1 dark:text-primary-300" />
|
||||||
<span class="leading-relaxed">{{ portfolio.profile.location }}</span>
|
<span class="leading-relaxed">{{ portfolio.profile.location }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="currentRole" class="flex items-center gap-1 text-base text-gray-700 dark:text-gray-200">
|
<div v-if="currentRole"
|
||||||
<img v-if="currentRole.companyLogo" :src="currentRole.companyLogo" :alt="`${currentRole.company} logo`"
|
class="flex items-center justify-between w-full text-base text-gray-700 dark:text-gray-200">
|
||||||
class="h-7 w-7 rounded-md object-contain" loading="lazy" />
|
<div class="flex items-center gap-1">
|
||||||
<span class="">{{ t('hero.currently') }}</span>
|
<img v-if="currentRole.companyLogo" :src="currentRole.companyLogo" :alt="`${currentRole.company} logo`"
|
||||||
<span class="font-semibold text-primary-600 dark:text-primary-300">
|
class="h-7 w-7 rounded-md object-contain" loading="lazy" />
|
||||||
<a v-if="currentRole.companyLink" :href="currentRole.companyLink" target="_blank" rel="noopener"
|
<span class="">{{ t('hero.currently') }}</span>
|
||||||
class="hover:underline text-primary-600 dark:text-primary-300">
|
<span class="font-semibold text-primary-600 dark:text-primary-300">
|
||||||
{{ currentRole.company }}
|
<a v-if="currentRole.companyLink" :href="currentRole.companyLink" target="_blank" rel="noopener"
|
||||||
</a>
|
class="hover:underline text-primary-600 dark:text-primary-300">
|
||||||
<span v-else>{{ currentRole.company }}</span>
|
{{ currentRole.company }}
|
||||||
</span>
|
</a>
|
||||||
|
<span v-else>{{ currentRole.company }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- Resume Button - Desktop only -->
|
||||||
|
<NuxtLink to="/resume" class="hidden sm:inline-flex items-center gap-2 px-4 py-2 text-sm font-semibold
|
||||||
|
bg-gradient-to-r from-primary-500 via-purple-500 to-pink-500
|
||||||
|
hover:from-primary-600 hover:via-purple-600 hover:to-pink-600
|
||||||
|
text-white rounded-full shadow-lg shadow-primary-500/25
|
||||||
|
transition-all duration-300 hover:scale-105 hover:shadow-xl hover:shadow-primary-500/40
|
||||||
|
animate-pulse hover:animate-none">
|
||||||
|
<UIcon name="i-heroicons-document-text" class="text-lg" />
|
||||||
|
<span>View Resume</span>
|
||||||
|
<UIcon name="i-heroicons-sparkles" class="text-sm opacity-80" />
|
||||||
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Resume Button - Mobile only -->
|
||||||
|
<NuxtLink to="/resume" class="sm:hidden inline-flex items-center justify-center gap-2 mt-2 px-4 py-2 text-sm font-medium
|
||||||
|
bg-gradient-to-r from-primary-500 via-purple-500 to-pink-500
|
||||||
|
hover:from-primary-600 hover:via-purple-600 hover:to-pink-600
|
||||||
|
text-white rounded-full shadow-lg shadow-primary-500/25
|
||||||
|
transition-all duration-300 hover:scale-105">
|
||||||
|
<UIcon name="i-heroicons-document-text" class="text-base" />
|
||||||
|
<span>View My Resume</span>
|
||||||
|
<UIcon name="i-heroicons-arrow-right" class="text-sm" />
|
||||||
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap items-center justify-center gap-3 sm:justify-start">
|
<div class="flex flex-wrap items-center justify-center gap-3 sm:justify-start">
|
||||||
<ClientTooltip :text="emailTooltip">
|
<ClientTooltip :text="emailTooltip">
|
||||||
|
|||||||
+10
-3
@@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-default">
|
<div class="layout-default" :key="layoutKey">
|
||||||
<TopNav client:only />
|
<TopNav />
|
||||||
<slot />
|
<main>
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
<FooterCopyright />
|
<FooterCopyright />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -16,6 +18,11 @@ import FooterCopyright from '@/components/common/FooterCopyright.vue'
|
|||||||
* Main layout for the application including TopNav and Footer.
|
* Main layout for the application including TopNav and Footer.
|
||||||
* This layout is used by default for all pages unless specified otherwise.
|
* This layout is used by default for all pages unless specified otherwise.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
// Force re-render when navigating back from pages with layout: false
|
||||||
|
const layoutKey = computed(() => route.fullPath)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
+25
-2
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: false
|
layout: false,
|
||||||
|
scrollToTop: true
|
||||||
})
|
})
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -12,11 +13,33 @@ useHead({
|
|||||||
{ name: 'robots', content: 'noindex' }
|
{ name: 'robots', content: 'noindex' }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Reset scroll position on mount
|
||||||
|
onMounted(() => {
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="min-h-screen">
|
<div class="min-h-screen bg-white dark:bg-gray-900">
|
||||||
|
<!-- Back to Home Button -->
|
||||||
|
<NuxtLink v-if="!isPrintMode" to="/" class="fixed top-4 left-4 z-50 inline-flex items-center gap-2 px-4 py-2 text-sm font-medium
|
||||||
|
bg-gray-100 dark:bg-gray-800 hover:bg-gray-200 dark:hover:bg-gray-700
|
||||||
|
text-gray-700 dark:text-gray-200 rounded-full shadow-lg
|
||||||
|
transition-all duration-200 hover:scale-105 no-print">
|
||||||
|
<UIcon name="i-heroicons-arrow-left" class="text-base" />
|
||||||
|
<span>Back to Home</span>
|
||||||
|
</NuxtLink>
|
||||||
|
|
||||||
<ResumePreview />
|
<ResumePreview />
|
||||||
<ResumeDownloadButton :is-print-mode="isPrintMode" />
|
<ResumeDownloadButton :is-print-mode="isPrintMode" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@media print {
|
||||||
|
.no-print {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user