tinybeast-services

This nuxt theme is suitable for service website
6,733
Install
npm install tinybeast-services
Latest Version:2.0.63
Vue:3
Last Updated:May 11, 2026
Links: npm
Maintainer: novustella

Tiny Beast theme: services

This nuxt theme is suitable for service website

Setup

Make sure to install the dependencies:

pnpm install

Working on your layer

The layer is at the root of this repository, it is exactly like a regular Nuxt project, except you can publish it on NPM.

The .playground directory should help you on trying your layer during development.

Running pnpm dev will prepare and boot .playground directory, which imports your layer itself.

Distributing your layer

Your Nuxt layer is shaped exactly the same as any other Nuxt project, except you can publish it on NPM.

To do so, you only have to check if files in package.json are valid, then run:

npm publish --access public

Once done, your users will only have to run:

npm install --save your-layer

Then add the dependency to their extends in nuxt.config:

defineNuxtConfig({
  extends: 'tinybeast-services'
})

Development Server

Start the development server on http://localhost:3000

pnpm dev

Production

Build the application for production:

pnpm build

Or statically generate it with:

pnpm generate

Locally preview production build:

pnpm preview

Storyblok

Storyblok is used for content management. To pull components from Storyblok, run:

storyblok pull-components --space <space_id>

storyblok cli 4

storyblok components --space <space_id> pull

To push components to Storyblok, run:

storyblok push-components --space <space_id> <path_to_schema_file>

storyblok cli 4

storyblok components push --space <space_id> --from <path_to_schema_file or space_id>

Required Environment Variables

  • BASE_URL=your_base_url
  • NUXT_PUBLIC_NODE_ENV=your_node_env
  • STORYBLOK_ACCESS_TOKEN=your_storyblok_access_token

Favicons

Add the following favicon files to the public/ directory (or .playground/public/ for development):

  • favicon.ico - Standard favicon (16x16 or 32x32)
  • favicon-16x16.png - 16x16 PNG favicon
  • favicon-32x32.png - 32x32 PNG favicon
  • apple-touch-icon.png - 180x180 PNG for Apple devices

These are configured in nuxt.config.ts and will be automatically included in all pages.

Internationalization (i18n)

This theme supports dynamic locale configuration through environment variables.

Default Behavior

By default, the site runs with Danish only (da) as a single-language website with clean URLs (no language prefixes).

Adding Multiple Languages

To enable multiple languages, set the following environment variables:

# Add multiple languages (JSON format)
NUXT_PUBLIC_I18N_LOCALES='[{"code":"da","name":"Danish","language":"da-DK"},{"code":"en","name":"English","language":"en-US"}]'

# Optionally change the default locale
NUXT_PUBLIC_I18N_DEFAULT_LOCALE='da'

Settings in Storyblok

You have to go and enable internationalization in Storyblok. Go to Settings > Internationalization and enable it. If you want AI translation, you can enable it in Settings > Labs > AI Translation.

Translatable Slugs (Field-Based Translation)

When using field-based translation mode (default), you can configure translatable slugs in Storyblok:

  1. Go to your story in Storyblok
  2. Click on the "Translate" tab
  3. Enable "Translatable slug" for each language
  4. Set custom slugs for each language (e.g., /contact in English becomes /kontakt in Danish)

Important: With field-based translation and the Translatable Slugs app:

  • The default language story lives at the original slug (e.g., /contact)
  • Translated versions use their translated slugs with language prefix (e.g., /da/kontakt)
  • The system uses Storyblok's alternates array (from Links API) or translated_slugs array (from Story API)
  • Only the translated slug URL will work for non-default languages (e.g., /da/kontakt works, /da/contact returns 404)
  • Sitemap automatically generates correct URLs for each language
  • Internal links in menu/footer automatically use translated slugs

Example:

  • English (default): /contact
  • Danish: /da/kontakt (NOT /da/contact - this will 404)
  • French: /fr/contact-nous (NOT /fr/contact - this will 404)

How it works:

  1. In Storyblok, the story has slug: "contact" and translated_slugs: [{lang: "da", path: "kontakt"}]
  2. When fetching with language: "da", Storyblok only recognizes the slug kontakt
  3. The menu/footer links check the alternates array and use the translated path
  4. The sitemap generates separate entries for each language with correct slugs

Examples

English + Danish:

NUXT_PUBLIC_I18N_LOCALES='[{"code":"da","name":"Danish","language":"da-DK"},{"code":"en","name":"English","language":"en-US"}]'

Multiple languages:

NUXT_PUBLIC_I18N_LOCALES='[{"code":"da","name":"Danish","language":"da-DK"},{"code":"en","name":"English","language":"en-US"},{"code":"fr","name":"French","language":"fr-FR"}]'

SEO Features

The theme automatically handles:

  • ✅ Canonical URLs with proper locale prefixes
  • ✅ Hreflang alternate links for international SEO
  • ✅ Open Graph locale tags (og:locale, og:locale:alternate)
  • ✅ Proper lang and dir attributes on HTML elements
  • ✅ Language-specific meta tags

URL Structure

  • Single language (Danish): /about, /contact
  • Multiple languages: /about (Danish), /en/about (English)

Changelog for important updates that either could break or should be known

2.0.23
  • Added support for contact form in CtaVariant2, component CtaVariant2.json should be pulled and pushed to Storyblok for field update.
2.0.25
  • Added support for a new form builder using resend for email notifications in HeroVariant2, component HeroVariant2.json should be pulled and pushed to Storyblok for field and component update. You should delete the old contact_form and form_item components and make sure you go through components where this is used and update them to use the new form builder.
  • new env variables needed:
    • RESEND_API_KEY=your_resend_api_key_here
    • FORM_RECIPIENT_EMAIL=recipient@yourdomain.com
    • FORM_SENDER_EMAIL=forms@yourdomain.com
    • FORM_EMAIL_SUBJECT="Ny formular indsendelse"
    • FORM_EMAIL_DESCRIPTION="Du har modtaget en ny formular indsendelse med følgende detaljer:"
  • components that you need to pull push and update: (main component.json are updated with all latest components but you still need to delete old components)
    • SbForm
    • SbFormField
    • form_field_option
    • HeroVariant3
    • hero-variant-2
    • CtaVariant2
2.0.30
  • Added the following new components that needs to be pushed to your project:
    • CardGridWithFilter
    • CardGridWithFilterItem
    • Progress
    • ProgressStep
    • Timeline
    • TimelineEvent
    • BentoGrid
    • BentoGridItem
2.0.48
  • Translatable Slugs Support: Added full support for Storyblok's translatable slugs feature in field-based translation mode
    • Pages now correctly resolve when accessed via translated slugs (e.g., /da/kontakt for Danish contact page)
    • Sitemap automatically generates correct URLs with translated slugs for each language
    • Internal links in components automatically use translated slugs when available
    • Prevents duplicate content issues by using language-specific slugs
    • Updated files:
      • app/pages/[...slug].vue - Added translated slug resolution logic
      • server/api/__sitemap__/urls.ts - Enhanced sitemap generation with translated slug support
      • app/composables/useStoryblokLinks.js - Added translated slug handling for internal links
    • See "Translatable Slugs (Field-Based Translation)" section for setup instructions
2.0.49
  • URL Improvements:
    • Configured Nuxt to remove trailing slashes from all URLs for cleaner, more SEO-friendly links
    • Added global middleware to redirect URLs with trailing slashes to non-trailing slash versions (301 redirect)
    • Ensures consistent URL structure across all hosting platforms (Vercel, Netlify, etc.)
    • Updated all components to use centralized getFormattedStoryblokLink composable for consistent link handling
    • Components updated: GlobalMenu, GlobalFooter, PricingVariant1, CardGridWithFilter, LogoCloudVariant2

Version History

Version Released Vue License
2.0.63 ^3.5.20
2.0.62 ^3.5.20
2.0.61 ^3.5.20
2.0.60 ^3.5.20
2.0.59 ^3.5.20