Fuck yeah, Nuxt makes perfect sense for your use case! Since you’re planning Vue integration later, this gives you a smooth migration path from static to dynamic. Here’s how your current setup would look in Nuxt:
// nuxt.config.ts
export default defineNuxtConfig({
devtools: { enabled: true },
// Generate static files
nitro: {
prerender: {
routes: [‘/’]
}
},
// CSS
css: [‘~/assets/scss/main.scss’],
// SEO & Meta
app: {
head: {
title: ‘Rim’,
meta: [
{ name: ‘description’, content: ‘Rim - kancelářský nábytek’ },
{ name: ‘viewport’, content: ‘width=device-width, initial-scale=1’ }
],
link: [
{ rel: ‘icon’, type: ‘image/x-icon’, href: ‘/favicon.ico’ }
]
}
},
// Auto-import components
components: true
})<!-- layouts/default.vue -->
<template>
<div class=“wrapper” :style=“wrapperStyles”>
<AppHeader />
<div class=“content-wrapper” id=“content”>
<slot />
</div>
<AppFooter />
</div>
</template>
<script setup>
// Dynamic wrapper styles based on page
const route = useRoute()
const wrapperStyles = computed(() => {
const styles = {}
if (route.name === ‘inspiration-detail’) {
styles[‘--accent-color’] = ‘#60BABA’
} else if (route.name === ‘designer-detail’) {
styles[‘--accent-color’] = ‘#AD7267’
}
return styles
})
</script><!-- pages/index.vue -->
<template>
<div>
<!-- Intro Slider -->
<section class=“intro-secondary”>
<div class=“intro-secondary-slider”>
<div class=“intro-secondary-slider__slides owl-carousel”>
<div
v-for=“slide in heroSlides”
:key=“slide.id”
class=“intro-secondary-slider-slide”
:class=“slide.modifierClass”
>
<div class=“intro-secondary-slider-slide__img”>
<picture v-if=“slide.type === ‘image’” class=“slider-image”>
<source :srcset=“slide.mobileSrc” media=“(max-width: 768px)“>
<img :src=“slide.src” alt=“”>
</picture>
<video
v-else
:poster=“slide.poster”
preload autoplay loop muted playsinline
>
<source type=“video/mp4" :src=“slide.src”>
</video>
</div>
<div class=“intro-secondary-slider-slide__inner”>
<div class=“container”>
<div class=“intro-secondary-slider-slide__content”>
<h1 class=“intro-secondary-slider-slide__title”>
<NuxtLink :to=“slide.link”>{{ slide.title }}</NuxtLink>
</h1>
<div class=“intro-secondary-slider-slide__perex apply-formatting”>
<p>{{ slide.excerpt }}</p>
</div>
<p class=“intro-secondary-slider-slide__button”>
<NuxtLink class=“button” :to=“slide.link”>{{ slide.buttonText }}</NuxtLink>
</p>
</div>
</div>
</div>
</div>
</div>
<div class=“slider-secondary-nav intro-secondary-slider__nav”>
<button class=“slider-nav__button slider-nav__button--prev” title=“Previous”>
<SvgIcon name=“arrow-left” />
</button>
<span class=“slider-nav__count”><span>1</span>/{{ heroSlides.length }}</span>
<button class=“slider-nav__button slider-nav__button--next” title=“Next”>
<SvgIcon name=“arrow-right” />
</button>
</div>
</div>
</section>
<!-- Featured Text -->
<section class=“section border-bottom featured-text-wrapper”>
<div class=“container”>
<div class=“featured-text”>
<div class=“row”>
<div class=“col-3 md:col-12”>
<div class=“featured-text__header”>
<div class=“featured-text__icon”>
<SvgIcon name=“rim-icon-primary” />
</div>
</div>
</div>
<div class=“col-8 md:col-12”>
<div class=“featured-text__content”>
<div class=“featured-text__text apply-formatting”>
<p>
Vyvíjíme a uvádíme na trh židle a nábytek do kancelářského prostředí,
které uspokojí zákazníky svým technickým řešením, designem, cenou a kvalitou.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Nav Cards -->
<section class=“section border-bottom nav-cards-wrapper”>
<SectionHeader title=“Produkty” />
<div class=“container”>
<div class=“nav-cards nav-cards--categories”>
<div class=“row”>
<div class=“col-3 md:col-6”>
<div class=“section-caption”>
<nav class=“section-caption__nav”>
<ul>
<li v-for=“category in categories” :key=“category.slug”>
<NuxtLink :to=“`/category/${category.slug}`“>{{ category.name }}</NuxtLink>
</li>
</ul>
</nav>
<NuxtLink to=“/products” class=“button section-caption__button”>
Všechny produkty
</NuxtLink>
</div>
</div>
<NavCard
v-for=“card in featuredCategories”
:key=“card.id”
:img=“card.img”
:title=“card.title”
:link=“card.link”
class=“col-3 md:col-6"
/>
</div>
</div>
</div>
</section>
<!-- Posts (News Mosaic) -->
<section class=“section border-bottom posts-wrapper”>
<SectionHeader title=“Svět Rim” />
<div class=“container”>
<div class=“posts posts--news posts--mosaic”>
<div class=“row”>
<div class=“col-8 md:col-12">
<PostCard
:img=“featuredNews.img”
:title=“featuredNews.title”
:excerpt=“featuredNews.excerpt”
:link=“featuredNews.link”
/>
</div>
<div class=“col-4 md:col-12”>
<PostCard
:img=“secondaryNews.img”
:title=“secondaryNews.title”
:excerpt=“secondaryNews.excerpt”
:link=“secondaryNews.link”
/>
</div>
<div class=“col-12">
<PostCard
:img=“tertiaryNews.img”
:title=“tertiaryNews.title”
:excerpt=“tertiaryNews.excerpt”
:link=“tertiaryNews.link”
/>
</div>
</div>
</div>
</div>
</section>
<!-- Reference Slider -->
<section class=“section bg-light post-slider-wrapper”>
<SectionHeader title=“Reference” />
<div class=“container”>
<div class=“post-slider”>
<div class=“post-slider__slides owl-carousel”>
<PostCard
v-for=“reference in references”
:key=“reference.id”
:img=“reference.img”
:title=“reference.title”
:excerpt=“reference.excerpt”
:link=“reference.link”
/>
</div>
<div class=“slider-nav post-slider__nav”>
<button class=“slider-nav__button slider-nav__button--prev” title=“Previous”>
<SvgIcon name=“arrow-left” />
</button>
<button class=“slider-nav__button slider-nav__button--next” title=“Next”>
<SvgIcon name=“arrow-right” />
</button>
</div>
</div>
</div>
</section>
</div>
</template>
<script setup>
// SEO
useSeoMeta({
title: ‘Rim - Domovská stránka’,
description: ‘Vyvíjíme a uvádíme na trh židle a nábytek do kancelářského prostředí’
})
// Data (will later come from CMS)
const heroSlides = [
{
id: 1,
type: ‘image’,
src: ‘root/content/homepage/intro-slider-slide-1.jpg’,
mobileSrc: ‘root/content/homepage/news-1.jpg’,
title: ‘Kloe’,
excerpt: ‘Nové kompletní řešení pro váš prostor’,
buttonText: ‘Více o kolekci’,
link: ‘/collection/kloe’,
modifierClass: ‘intro-secondary-slider-slide--secondary’
},
{
id: 2,
type: ‘video’,
src: ‘./root/content/homepage/811-822-pov_fhd_best_2.mp4’,
poster: ‘./root/content/homepage/intro-slider-slide-1.jpg’,
title: ‘Lambda’,
excerpt: ‘Nadčasový design s nádechem přírody prostor prostor’,
buttonText: ‘Více o kolekci’,
link: ‘/collection/lambda’
}
]
const categories = [
{ slug: ‘kancelarske-zidle’, name: ‘Kancelářské židle’ },
{ slug: ‘konferencni-zidle’, name: ‘Konferenční židle’ },
{ slug: ‘kresla’, name: ‘Křesla’ },
// ... more categories
]
const featuredCategories = [
{
id: 1,
img: ‘root/content/categories/1.jpg’,
title: ‘Kancelářské židle’,
link: ‘/category/kancelarske-zidle’
},
{
id: 2,
img: ‘root/content/categories/2.jpg’,
title: ‘Konferenční židle’,
link: ‘/category/konferencni-zidle’
},
{
id: 3,
img: ‘root/content/categories/3.jpg’,
title: ‘Křesla’,
link: ‘/category/kresla’
}
]
const featuredNews = {
img: ‘root/content/homepage/news-1.jpg’,
title: ‘Nový showroom Praha’,
excerpt: ‘<p>Poprvé v historii soutěže se nám podařilo získat hned dvě ocenění...</p>‘,
link: ‘/news/novy-showroom-praha’
}
// ... more data objects
</script><!-- components/NavCard.vue -->
<template>
<div class=“nav-card-wrapper”>
<NuxtLink :to=“link || ‘#’“>
<div class=“nav-card”>
<div v-if=“img” class=“cover nav-card__img”>
<img :src=“img” :alt=“title” />
</div>
<div class=“nav-card__content”>
<h3 v-if=“title” class=“nav-card__title”>{{ title }}</h3>
<SvgIcon name=“arrow-right” class=“nav-card__icon” />
</div>
</div>
</NuxtLink>
</div>
</template>
<script setup>
interface Props {
img?: string
title?: string
link?: string
}
defineProps<Props>()
</script><!-- components/SectionHeader.vue -->
<template>
<header class=“section-header”>
<div class=“container”>
<div class=“section-header__inner”>
<div v-if=“subtitle” class=“section-header__subtitle”>{{ subtitle }}</div>
<h2 v-if=“title” class=“section-header__title”>{{ title }}</h2>
<div v-if=“perex” class=“section-header__perex apply-formatting” v-html=“perex”></div>
</div>
</div>
</header>
</template>
<script setup>
interface Props {
title?: string
subtitle?: string
perex?: string
}
defineProps<Props>()
</script><!-- components/SvgIcon.vue -->
<template>
<span class=“icon” :class=“`icon--${name}`“>
<svg>
<use :href=“`/public/images/sprite.svg#${name}`“></use>
</svg>
</span>
</template>
<script setup>
interface Props {
name: string
}
defineProps<Props>()
</script><!-- components/AppHeader.vue -->
<template>
<header class=“header” id=“header”>
<div class=“header__top”>
<div class=“container”>
<NuxtLink class=“header__logo” to=“/”>
<SvgIcon name=“logo” />
</NuxtLink>
<nav class=“header__nav-secondary”>
<ul>
<li><NuxtLink to=“/about”>O nás</NuxtLink></li>
<li><NuxtLink to=“#” class=“is-active”>Pro architekty</NuxtLink></li>
<li><NuxtLink to=“/downloads”>Ke stažení</NuxtLink></li>
<li>
<a href=“#” class=“dropdown-trigger”>
SharePoint
<SvgIcon name=“external-link” />
</a>
<div class=“header__dropdown”>
<ul>
<li><a href=“#”>CZ</a></li>
<li><a href=“#”>SK</a></li>
</ul>
</div>
</li>
</ul>
</nav>
<div class=“lang-switch”>
<div class=“lang-switch__selected”>
<SvgIcon name=“globe” />
{{ currentLang }}
</div>
<ul class=“lang-switch__dropdown”>
<li v-for=“lang in languages” :key=“lang.code”>
<button
@click=“switchLanguage(lang.code)”
:class=“{ ‘is-active’: currentLang === lang.code }”
>
{{ lang.name }}
</button>
</li>
</ul>
</div>
</div>
</div>
<div class=“header__bottom”>
<div class=“container”>
<NuxtLink class=“header__logo-secondary” to=“/”>
<SvgIcon name=“logo” />
</NuxtLink>
<nav class=“header__nav-primary”>
<ul>
<li>
<NuxtLink to=“/products”>Produkty</NuxtLink>
<AppSubmenu />
</li>
<li><NuxtLink to=“/designers” :class=“{ ‘is-active’: $route.path.includes(‘designers’) }“>Designéři</NuxtLink></li>
<li><NuxtLink to=“/inspiration”>Inspirace</NuxtLink></li>
<li><NuxtLink to=“/references”>Reference</NuxtLink></li>
<li><NuxtLink to=“/stores”>Prodejny</NuxtLink></li>
<li><NuxtLink to=“/contact”>Kontakt</NuxtLink></li>
</ul>
</nav>
<div class=“header__actions”>
<button @click=“openSearch” class=“header-action header-action--search”>
<SvgIcon name=“search” />
Vyhledat
</button>
</div>
</div>
</div>
</header>
</template>
<script setup>
const route = useRoute()
const currentLang = ref(‘CZ’)
const languages = [
{ code: ‘CZ’, name: ‘Česky’ },
{ code: ‘EN’, name: ‘English’ },
{ code: ‘DE’, name: ‘Deutsch’ }
]
const switchLanguage = (code: string) => {
currentLang.value = code
// Handle language switching logic
}
const openSearch = () => {
// Handle search modal opening
}
</script>- Smooth Vue transition - When you’re ready for CMS integration, you just replace the hardcoded data with API calls
- Type safety - Full TypeScript support
- Static generation -
nuxt generatecreates pure HTML files - SEO optimized - Built-in meta management
- Modern tooling - Vite, hot reload, dev tools
- Component reusability - Perfect for your component-heavy design
- Auto-imports - Components and composables auto-imported
- File-based routing - Each page is just a file in
/pages
- Start with layout - Convert header/footer first
- Move static data - Keep your current content structure, just move data to script sections
- Convert components - One by one, starting with simple ones
- Keep your SCSS - Works perfectly with Nuxt
- Add dynamic features gradually - Search, filtering, etc.
When you’re ready for CMS integration, you just:
- Replace static data with
$fetch()calls to your API - Add dynamic routing (
[slug].vuefiles) - Keep all your components exactly the same
This approach gives you the best of both worlds - static generation now, easy Vue app transition later. Want me to show you how to set this up or dive deeper into any specific part?