Portfolio Page Vuetify
April 13, 2025 Β· AI Conversations
—
### β PortfolioPage.vue (Full Component)
<template>
<v-container class="my-10">
<v-row>
<v-col cols="12" class="text-center mb-8">
<h1 class="text-h4 font-weight-bold">My Portfolio</h1>
<p class="text-subtitle-1">Projects I've worked on</p>
</v-col>
<v-col
v-for="(project, index) in portfolioItems"
:key="index"
cols="12"
sm="6"
md="4"
>
<v-card class="elevation-3">
<v-img
:src="project.image"
height="200px"
cover
></v-img>
<v-card-title>{{ project.title }}</v-card-title>
<v-card-text>{{ project.description }}</v-card-text>
<v-card-actions>
<v-btn :href="project.link" target="_blank" color="primary" variant="flat">
View Project
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script setup>
import { ref } from 'vue'
const portfolioItems = ref([
{
title: 'Project One',
description: 'A web app built with Vue.js and Firebase.',
image: 'https://via.placeholder.com/400x200',
link: 'https://example.com/project1'
},
{
title: 'Project Two',
description: 'Landing page built using Vuetify.',
image: 'https://via.placeholder.com/400x200',
link: 'https://example.com/project2'
},
{
title: 'Project Three',
description: 'Mobile-first design for a startup.',
image: 'https://via.placeholder.com/400x200',
link: 'https://example.com/project3'
}
])
</script>
—
### π Optional Styling (Scoped if needed)
<style scoped>
.v-card {
transition: transform 0.3s ease;
}
.v-card:hover {
transform: scale(1.03);
}
</style>
—
### β
Add It to Router
If you're using Vue Router, add this to your router config:
{
path: '/portfolio',
name: 'Portfolio',
component: () => import('@/views/PortfolioPage.vue'),
}
Would you like this page to also include filters or categories? Or animated transitions?
—
### π `src/types/PortfolioItem.ts`
export interface PortfolioItem {
title: string
description: string
image: string
link: string
}
—
### π Update in `PortfolioPage.vue`
<script setup lang="ts">
import { ref } from 'vue'
import type { PortfolioItem } from '@/types/PortfolioItem'
const portfolioItems = ref<PortfolioItem[]>([
{
title: 'Project One',
description: 'A web app built with Vue.js and Firebase.',
image: 'https://via.placeholder.com/400x200',
link: 'https://example.com/project1'
},
{
title: 'Project Two',
description: 'Landing page built using Vuetify.',
image: 'https://via.placeholder.com/400x200',
link: 'https://example.com/project2'
},
{
title: 'Project Three',
description: 'Mobile-first design for a startup.',
image: 'https://via.placeholder.com/400x200',
link: 'https://example.com/project3'
}
])
</script>
—
### π Folder Structure Suggestion
src/
β
βββ types/
β βββ PortfolioItem.ts
β
βββ views/
β βββ PortfolioPage.vue
—
Let me know if you'd like to split the description or add tags/tech stack to each item in the interface too.
portfolioItems.value = await fetchPortfolioItems() as PortfolioItem[]
}
const fetchPortfolioCategories = async () => {
portfolioCategories.value = await fetchPortfolioCategories() as PortfolioCategory[]
}
Conversion of type 'void' to type 'PortfolioItem[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.ts-plugin(2352)
You're likely doing something like:
const fetchPortfolioItems = async () => {
portfolioItems.value = await fetchPortfolioItems() as PortfolioItem[]
}
Here, you're defining a function called `fetchPortfolioItems`, and inside it, youβre calling the same function β which results in an infinite loop and incorrect typing.
—
### β Correct Way
You need to call **another function** (maybe an API utility), not the one youβre declaring. For example:
#### 1. **Create an API function** in `@/services/portfolio.ts`
// src/services/portfolio.ts
import type { PortfolioItem, PortfolioCategory } from '@/types/PortfolioItem'
export const getPortfolioItems = async (): Promise<PortfolioItem[]> => {
// Simulating fetch with dummy data or use actual API call
return [
{
title: 'Project One',
description: 'Vue + Firebase app',
image: 'https://via.placeholder.com/400x200',
link: 'https://example.com/project1'
}
]
}
export const getPortfolioCategories = async (): Promise<PortfolioCategory[]> => {
return [
{ id: 1, name: 'Web Development' },
{ id: 2, name: 'Mobile App' }
]
}
—
#### 2. **Use inside your component**
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { PortfolioItem, PortfolioCategory } from '@/types/PortfolioItem'
import { getPortfolioItems, getPortfolioCategories } from '@/services/portfolio'
const portfolioItems = ref<PortfolioItem[]>([])
const portfolioCategories = ref<PortfolioCategory[]>([])
const fetchPortfolioItems = async () => {
portfolioItems.value = await getPortfolioItems()
}
const fetchPortfolioCategories = async () => {
portfolioCategories.value = await getPortfolioCategories()
}
onMounted(() => {
fetchPortfolioItems()
fetchPortfolioCategories()
})
</script>
—
### π§Ύ Optional Interface
Add this to `PortfolioItem.ts`:
export interface PortfolioItem {
title: string
description: string
image: string
link: string
}
export interface PortfolioCategory {
id: number
name: string
}
—
Let me know if you want to connect this to a real API endpoint or simulate delays using `setTimeout`.
7 } from '@/dbstore/firebase/myPortfolio'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
exist but give error in yarn buiold
—
### β 1. **Path Alias `@` Not Recognized in Production**
When using `@` for aliasing (`@/dbstore/firebase/myPortfolio`), your `vite.config.ts` must have the alias configured **correctly**.
#### π Check this in `vite.config.ts`:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'), // π this line is required
},
},
})
—
### β 2. **Case Sensitivity (Especially on Linux Servers)**
Check that the filename and folder names are **exactly** correct. For example:
If your import is:
import { getPortfolioData } from '@/dbstore/firebase/myPortfolio'
Make sure the actual file path is:
src/dbstore/firebase/myPortfolio.ts
β
NOT:
– `MyPortfolio.ts`
– `myportfolio.ts`
– `myportfolio.js`
Linux-based build systems (e.g. Netlify, Vercel, most CI/CD) are **case-sensitive**, unlike Windows.
—
### β 3. **Missing `.ts` Extension in TypeScript Declaration**
If the file is `.ts` but you're importing something like:
import myPortfolio from '@/dbstore/firebase/myPortfolio'
TypeScript will infer `.ts` **only if the path resolves properly**. But on build, if thereβs no corresponding `.d.ts` file (or incorrect config), it may break.
To be safe, try:
import myPortfolio from '@/dbstore/firebase/myPortfolio.ts'
But usually, with a correct alias, this isn't needed.
—
### β 4. **Clear Cache & Rebuild**
Sometimes Vite or Yarn caches mess things up.
Try:
rm -rf node_modules dist .vite
yarn cache clean
yarn install
yarn build
—
Let me know:
– your `vite.config.ts`
– and folder structure for `src/dbstore/firebase/myPortfolio.ts`
β¦if it's still not working. I can help spot the exact issue.
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import vueDevTools from 'vite-plugin-vue-devtools'
import nightwatchPlugin from 'vite-plugin-nightwatch'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx(),
vueDevTools(),
nightwatchPlugin(),
],
server: {
port: 5185,
strictPort: true,
origin: 'http://localhost:5185',
watch: {
ignored: ['**/node_modules/**', '**/vendor/**'],
usePolling: true,
},
proxy: {
'/api': {
target: 'http://ec2-51-20-60-238.eu-north-1.compute.amazonaws.com/api',
changeOrigin: true,
rewrite: (path) => path.replace(/^/api/, ''),
},
},
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
})
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
So if you're getting the error **during `yarn build`**:
Cannot find module '@/dbstore/firebase/myPortfolio' or its corresponding type declarations.
Here are the most likely causes and fixes:
—
### β 1. **Check the actual file exists:**
Ensure the file is located exactly at:
src/dbstore/firebase/myPortfolio.ts
βοΈ Make sure:
– The folder and file names match **exactly**.
– You're not accidentally naming it like `myportfolio.ts` (lowercase "P"), which works on Windows but fails in build (Linux is case-sensitive).
—
### β 2. **Check file extension in import (Optional)**
This should be fine:
import { getPortfolioData } from '@/dbstore/firebase/myPortfolio'
β¦but for debugging, test it once like:
import { getPortfolioData } from '@/dbstore/firebase/myPortfolio.ts'
If this fixes it, the issue is with Vite not resolving the extension properly β but this is rare unless some plugin is interfering.
—
### β 3. **Restart Vite, Clear Cache**
Sometimes Viteβs build cache causes weird resolution issues. Run:
rm -rf dist node_modules .vite
yarn cache clean
yarn install
yarn build
—
### β 4. **Verify TS config paths (optional)**
Check your `tsconfig.json` has path mappings, though this isnβt required for Vite, it helps IDEs and may avoid errors:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
Then restart your editor (VSCode, etc.) to make sure it's picked up.
—
### β 5. **Wrong default export or no export**
Make sure your `myPortfolio.ts` file **exports something** like:
export const getPortfolioData = async () => {
// your logic
}
Not:
const getPortfolioData = () => { ... } // β no export
—
### Want me to review the `myPortfolio.ts` file content or file tree?
Paste the path and top part of that file β happy to help!
—
## β Fix: Add `baseUrl` & `paths` in `tsconfig.json`
Even though Vite handles `@` during build, TypeScript also needs to know how to resolve it **especially in type checking during build**.
### π§ `tsconfig.json`:
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"types": ["vite/client"]
}
}
> β Restart your editor after editing `tsconfig.json`.
—
## β Fix: Use Relative Import (Quick Bypass)
If you're in a rush, temporarily change:
import { getPortfolioData } from '@/dbstore/firebase/myPortfolio'
to:
import { getPortfolioData } from '../../dbstore/firebase/myPortfolio'
β¦depending on your current fileβs depth.
> This confirms whether it's purely an alias issue or something else (like case or missing file).
—
## β Confirm: File location and naming
Make sure the file exists exactly here:
src/dbstore/firebase/myPortfolio.ts
Run this to confirm:
ls -l src/dbstore/firebase/
If it's `MyPortfolio.ts` (capital "M") it will fail on `@/dbstore/firebase/myPortfolio`.
—
## β Clean Cache and Rebuild
rm -rf node_modules dist .vite
yarn cache clean
yarn install
yarn build
—
If this still doesn't resolve the issue, feel free to:
– Share the folder path of `myPortfolio.ts`
– Or share the error after trying the `tsconfig` fix
Iβll get it working with you fast.
33 import myimage from '../assets/images/myimage.png';
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/dbstore/firebase/myPortfolio.ts:1:29 – error TS2307: Cannot find module '@/firebase' or its corresponding type declarations.
1 import { db, storage } from '@/firebase'
—
## β Fix 1: Support Importing `.png` and Other Assets
TypeScript doesnβt know how to handle image imports by default. You need to declare the module type.
### β Add `src/types/shims.d.ts` (or `globals.d.ts`)
// src/types/shims.d.ts
declare module '*.png' {
const value: string
export default value
}
You can also include JPEG, SVG, etc., like this:
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.svg'
declare module '*.gif'
—
## β Fix 2: Make TypeScript recognize `@` alias
Even though your `vite.config.ts` has:
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
β¦TypeScript **needs the same alias defined in `tsconfig.json`**.
### π `tsconfig.json` (add this if missing):
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
Then **restart your editor** so it can reload the config.
—
## β Bonus: Clean and Rebuild
After changes:
rm -rf node_modules dist .vite
yarn cache clean
yarn install
yarn build
—
## β Summary
| Issue | Fix |
|——————————-|———————————————————|
| TS2307 for `.png` | Add a module declaration in `shims.d.ts` |
| TS2307 for `@/firebase` | Define path alias in `tsconfig.json` |
| Still failing after fix | Restart editor + clear `.vite`, `node_modules`, `dist` |
Let me know if you want me to generate a ready `shims.d.ts` file or verify your `tsconfig.json`.