Upgrade to Nuxt 4 and fix icon issues
- Upgrade from Nuxt 3.6.0 to Nuxt 4.3.1 - Replace nuxt-icon with @nuxt/icon (Nuxt 4 compatible) - Install missing icon collections (@iconify-json/ion, heroicons, etc.) - Fix icon colors: use style instead of color prop - Add AGENTS.md with coding guidelines - Fix icon alignment in index.vue (items-center)
This commit is contained in:
parent
72d2d67842
commit
61332c28ef
131
AGENTS.md
Normal file
131
AGENTS.md
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
# AGENTS.md - Agent Coding Guidelines
|
||||
|
||||
This document provides guidelines for agents working on this codebase.
|
||||
|
||||
## Project Overview
|
||||
|
||||
- **Framework**: Nuxt 3 (Vue 3)
|
||||
- **Styling**: Tailwind CSS
|
||||
- **State Management**: Pinia
|
||||
- **UI Components**: Headless UI + Nuxt Icon
|
||||
- **Image Handling**: @nuxt/image
|
||||
- **TypeScript**: Enabled (tsconfig extends .nuxt/tsconfig.json)
|
||||
- **Storybook**: Available for component documentation
|
||||
|
||||
## Build Commands
|
||||
|
||||
```bash
|
||||
# Development
|
||||
npm run dev # Start development server
|
||||
npm run build # Build for production
|
||||
npm run generate # Generate static site (SSG)
|
||||
npm run preview # Preview production build
|
||||
|
||||
# No test framework configured
|
||||
```
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### General Conventions
|
||||
|
||||
- Use Vue 3 Composition API with `<script setup lang="ts">`
|
||||
- TypeScript is preferred for new files; stores use JavaScript (.js)
|
||||
- Follow Nuxt 3 auto-import conventions (no explicit imports for composables, components, etc.)
|
||||
|
||||
### File Organization
|
||||
|
||||
```
|
||||
/pages/ - Page components (file-based routing)
|
||||
/components/ - Vue components (auto-imported)
|
||||
/layouts/ - Layout components
|
||||
/server/api/ - Server API routes (Nitro)
|
||||
/stores/ - Pinia stores (.js files)
|
||||
/assets/ - Static assets
|
||||
/public/ - Public static files
|
||||
```
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- **Components**: PascalCase (e.g., `Modal.vue`, `IconButton.vue`)
|
||||
- **Files**: kebab-case for pages, PascalCase for components
|
||||
- **Stores**: CamelCase (e.g., `ModalStore.js`, `AudioPlayerStore.js`)
|
||||
- **Props/Emits**: camelCase
|
||||
|
||||
### Component Patterns
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// Use withDefaults for optional props
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue?: boolean
|
||||
persistent?: boolean
|
||||
}>(),
|
||||
{
|
||||
modelValue: false,
|
||||
persistent: false,
|
||||
},
|
||||
)
|
||||
|
||||
// Use type-only emits
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: boolean): void
|
||||
}>()
|
||||
|
||||
// Use toRefs for reactive destructuring
|
||||
const { modelValue } = toRefs(props)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Template content -->
|
||||
</template>
|
||||
```
|
||||
|
||||
### Tailwind CSS
|
||||
|
||||
- Use Tailwind utility classes for all styling
|
||||
- Common classes used: `flex`, `grid`, `fixed`, `relative`, `z-*`, `p-*`, `m-*`, `text-*`, etc.
|
||||
|
||||
### API Routes (Server)
|
||||
|
||||
```typescript
|
||||
// server/api/example.ts
|
||||
export default defineEventHandler((event) => {
|
||||
// Handle request and return data
|
||||
})
|
||||
```
|
||||
|
||||
### Store Patterns (Pinia)
|
||||
|
||||
```javascript
|
||||
// stores/ExampleStore.js
|
||||
import { defineStore } from "pinia"
|
||||
|
||||
export const useExampleStore = defineStore("ExampleStore", {
|
||||
state: () => ({ count: 0 }),
|
||||
actions: {
|
||||
increment() {
|
||||
this.count++
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
- Use try/catch in API routes
|
||||
- Return appropriate HTTP status codes
|
||||
- Handle undefined/null values gracefully
|
||||
|
||||
### Imports
|
||||
|
||||
- Vue/composables: Use Nuxt auto-imports (no import needed)
|
||||
- External modules: Explicit import
|
||||
- Server-only: Place in `/server/` directory
|
||||
- Path aliases: `@/` maps to project root
|
||||
|
||||
### Additional Notes
|
||||
|
||||
- Project uses Storybook (`.stories.ts` files) for component documentation
|
||||
- Environment variables should use `.env` files (not committed)
|
||||
- Image domains configured for `unboundedpress.org` in nuxt.config.ts
|
||||
|
|
@ -75,7 +75,7 @@ const toggle = () => {
|
|||
<Icon
|
||||
name="heroicons:chevron-down"
|
||||
:class="isOpen ? 'transform rotate-180' : ''"
|
||||
class="w-5 h-5"
|
||||
class="w-5 h-5 text-black"
|
||||
/>
|
||||
<slot name="title"></slot>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue'
|
||||
import { ref, toRefs, watch } from 'vue'
|
||||
import Icon from '../Icon/index.vue'
|
||||
import Collapsible from './Collapsible.vue'
|
||||
|
||||
interface CollapsibleItem {
|
||||
|
|
|
|||
|
|
@ -3,35 +3,35 @@
|
|||
<div v-show="visible" class="bg-black rounded-full text-xs inline-flex" >
|
||||
|
||||
<NuxtLink v-if="type === 'score'" :to="link" class="inline-flex p-1">
|
||||
<Icon name="ion:book-sharp" color="white" />
|
||||
<Icon name="ion:book-sharp" style="color: white" />
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink v-else-if="type === 'document'" class="inline-flex p-1" :to="link" :target="newTab ? '_blank' : undefined">
|
||||
<Icon name="ion:book-sharp" color="white" />
|
||||
<Icon name="ion:book-sharp" style="color: white" />
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink v-else-if="type === 'buy'" class="inline-flex p-1" :to="link">
|
||||
<Icon name="bxs:purchase-tag" color="white" />
|
||||
<Icon name="bxs:purchase-tag" style="color: white" />
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink v-else-if="type === 'email'" class="inline-flex p-1" :to="link">
|
||||
<Icon name="ic:baseline-email" color="white" />
|
||||
<Icon name="ic:baseline-email" style="color: white" />
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink v-else-if="type === 'discogs'" class="inline-flex p-1" :to="link">
|
||||
<Icon name="simple-icons:discogs" color="white" />
|
||||
<Icon name="simple-icons:discogs" style="color: white" />
|
||||
</NuxtLink>
|
||||
|
||||
<button @click="audioPlayerStore.setSoundCloudTrackID(work.soundcloud_trackid)" v-else-if="type === 'audio'" class="inline-flex p-1">
|
||||
<Icon name="wpf:speaker" color="white" />
|
||||
<Icon name="wpf:speaker" style="color: white" />
|
||||
</button>
|
||||
|
||||
<button @click="modalStore.setModalProps('video', 'aspect-video', true, '', '', work.vimeo_trackid)" v-else-if="type === 'video'" class="inline-flex p-1">
|
||||
<Icon name="fluent:video-48-filled" color="white" />
|
||||
<Icon name="fluent:video-48-filled" style="color: white" />
|
||||
</button>
|
||||
|
||||
<button @click="modalStore.setModalProps('image', 'aspect-auto', true, 'images', work.gallery, '')" v-else="type === 'image'" class="inline-flex p-1">
|
||||
<Icon name="mdi:camera" color="white" />
|
||||
<Icon name="mdi:camera" style="color: white" />
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxtjs/tailwindcss', '@nuxt/image', 'nuxt-icon', '@pinia/nuxt', 'nuxt-headlessui', 'nuxt-swiper'],
|
||||
extends: ['nuxt-umami'],
|
||||
modules: ['@nuxtjs/tailwindcss', '@nuxt/image', '@nuxt/icon', '@pinia/nuxt', 'nuxt-headlessui', 'nuxt-swiper', 'nuxt-umami'],
|
||||
image: {
|
||||
domains: ['unboundedpress.org']
|
||||
},
|
||||
|
|
|
|||
30
package.json
30
package.json
|
|
@ -9,19 +9,27 @@
|
|||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/image": "^1.0.0-rc.1",
|
||||
"@nuxtjs/tailwindcss": "^6.7.0",
|
||||
"@types/node": "^18",
|
||||
"nuxt-headlessui": "^1.1.4",
|
||||
"nuxt-icon": "^0.4.1"
|
||||
"@iconify-json/bxs": "^1.2.2",
|
||||
"@iconify-json/fluent": "^1.2.39",
|
||||
"@iconify-json/heroicons": "^1.2.3",
|
||||
"@iconify-json/ion": "^1.2.6",
|
||||
"@iconify-json/mdi": "^1.2.3",
|
||||
"@iconify-json/simple-icons": "^1.2.71",
|
||||
"@iconify-json/wpf": "^1.2.0",
|
||||
"@nuxt/icon": "^2.2.1",
|
||||
"@nuxt/image": "^2.0.0",
|
||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||
"@types/node": "^25.2.3",
|
||||
"nuxt-headlessui": "^1.2.2",
|
||||
"nuxt-icon": "^1.0.0-beta.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pinia/nuxt": "^0.4.11",
|
||||
"@pinia/nuxt": "^0.11.3",
|
||||
"mongodb": "^7.1.0",
|
||||
"nuxt": "^3.6.0",
|
||||
"nuxt-swiper": "^1.1.0",
|
||||
"nuxt-umami": "^2.4.2",
|
||||
"pinia": "^2.1.3",
|
||||
"sharp": "^0.32.1"
|
||||
"nuxt": "^4.3.1",
|
||||
"nuxt-swiper": "^2.0.1",
|
||||
"nuxt-umami": "^3.2.1",
|
||||
"pinia": "^3.0.4",
|
||||
"sharp": "^0.34.5"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<div class="py-2 ml-3" v-for="item in works">
|
||||
<p class="font-thin">{{ item.year }}</p>
|
||||
<div class="leading-tight py-1 ml-3" v-for="work in item.works">
|
||||
<div class="grid grid-cols-[65%,30%] gap-1 font-thin">
|
||||
<div class="grid grid-cols-[65%,30%] gap-1 font-thin items-center">
|
||||
<div class="italic text-sm">{{ work.title }}</div>
|
||||
<div class="inline-flex">
|
||||
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
<p class="text-lg">writings</p>
|
||||
|
||||
<div class="leading-tight py-2 ml-3 text-sm" v-for="item in pubs">
|
||||
<div class="grid grid-cols-[95%,5%] gap-1">
|
||||
<div class="grid grid-cols-[95%,5%] gap-1 items-center">
|
||||
<div>
|
||||
<span v-html="item.entryTags.title"></span>
|
||||
<div class="ml-4 text-[#7F7F7F]">
|
||||
|
|
|
|||
Loading…
Reference in a new issue