Little Island - Irish Pub Frýdek-Místek

Site for an authentic Irish pub operating since 2009. Guinness on tap, 50+ whiskeys, weekend live music, private events up to 40 guests. Dark "Irish pub" aesthetic, premium photography, event bookings.

Next.jsTypeScriptTailwind CSSResendVercel

Open since 2009

Brief

Little Island is an Irish pub in Frýdek-Místek (Czech Republic), open since 2009. Guinness on tap, 50+ whiskeys, weekend live music, private events up to 40 guests. The client needed a marketing site that:

  1. Reflects the pub's atmosphere (dark wood, warm light, music) - not corporate cleanliness
  2. Acts as a booking funnel for private events
  3. Communicates the live music program
  4. Carries SEO authority for local search ("Irish pub Frýdek", "Guinness Frýdek")
  5. The client is a restaurateur, not a content marketer - the site must run for months without updates

Budget and runway weren't generous. I built static Next.js, no headless CMS, MDX-driven content where it makes sense.

Brand language in CSS

A gift for the frontend designer: "Irish pub feeling" in digital form. What does that mean?

  • Warm colors: not pure black #000, but #1A140E (coffee wood). Not white #FFF, but #F5EFE2 (candlelight).
  • Serif accent fonts: headings in Cormorant Garamond (classic serif), body in Inter (neutral). Logo + accent strings in stylized Caveat (handwritten feel).
  • Texture background: subtle wood-grain SVG noise overlay (10 % opacity), not flat color. Generated via feTurbulence SVG filter, so I don't ship a 200 kB texture.
  • Accent IRISH GREEN (#0A6B3F, not Vercel-neon green). For CTAs and hover states.
/* tailwind.config.ts color palette */
colors: {
  pub: {
    bg: '#1A140E',          // dark wood background
    surface: '#241A12',     // panel/card
    parchment: '#F5EFE2',   // body text on dark
    cream: '#E8DCC4',       // subtle highlight
    irish: '#0A6B3F',       // brand green
    amber: '#C68642',       // whiskey accent
  },
}

Test: I showed the mock to 5 people ("describe the first impression"). Out of 5: "cozy", "Irish pub", "old school", "no startup vibes", "smell of wood". Brand language is load-bearing UX, not decoration.

Booking flow

Private events (birthdays, corporate team-builds, weddings) are the main revenue stream beyond regular gastronomy. Form → email → manual confirmation.

// src/app/api/booking/route.ts
import { Resend } from 'resend';
import { z } from 'zod';
 
const resend = new Resend(process.env.RESEND_API_KEY!);
 
const BookingSchema = z.object({
  name: z.string().min(2).max(80),
  email: z.string().email(),
  phone: z.string().min(9).max(20),
  date: z.string(), // ISO date
  guests: z.number().int().min(5).max(40),
  occasion: z.string().max(200),
  honeypot: z.string().max(0).optional(), // anti-bot
});
 
export async function POST(req: Request) {
  const body = await req.json();
  const parsed = BookingSchema.safeParse(body);
  if (!parsed.success || parsed.data.honeypot) {
    return new Response('invalid', { status: 400 });
  }
 
  const data = parsed.data;
 
  // 1) email to owner
  await resend.emails.send({
    from: 'reservations@littleisland.cz',
    to: 'owner@littleisland.cz',
    replyTo: data.email,
    subject: `Booking ${data.date} - ${data.guests} guests`,
    html: renderOwnerEmail(data),
  });
 
  // 2) confirmation to guest
  await resend.emails.send({
    from: 'Little Island <reservations@littleisland.cz>',
    to: data.email,
    subject: 'Your request received - we will reply within 24h',
    html: renderGuestEmail(data),
  });
 
  return new Response('ok');
}

No realtime calendar, no availability lookup. Manual confirmation by the owner, because private events need negotiation (catering, opening hours, specific PA setup). A semi-form with explicit "we'll reply within 24h" lowers expectations of instant booking and paradoxically raises lead quality (users expecting instant booking are 70 % no-shows).

Whiskey catalog

50+ whiskeys, categorized by style (Single Malt, Blended, Bourbon, Irish, Rye). Built as MDX entries:

content/whiskey/
├── jameson-original.mdx
├── tullamore-dew.mdx
├── connemara-peated.mdx
└── redbreast-12.mdx

Frontmatter:

---
name: 'Connemara Peated'
category: 'Irish Single Malt'
abv: 40
priceCzk: 120
notes: 'The only peated Irish whiskey. Smoke, vanilla, light honey.'
origin: 'Cooley Distillery, IE'
---

UI filter: category + price range + ABV. No DB, all static. Tailwind grid layout, hover popup with notes. The client adds a new whiskey = one MDX file + commit + Vercel rebuild. Not a CMS dashboard.

Live music calendar + ICS export

Weekend program - a guitarist or band - changes every month. Content is in MDX:

content/events/
├── 2026-02-15-tom-collins.mdx
├── 2026-02-22-the-emerald-band.mdx
└── 2026-03-01-irish-folk-trio.mdx

I added ICS export for each event. A visitor can click "Add to calendar" and download an RFC 5545 file:

// src/app/api/events/[slug]/ics/route.ts
export async function GET(_req: Request, { params }: { params: { slug: string } }) {
  const event = await getEvent(params.slug);
  if (!event) return new Response('not found', { status: 404 });
 
  const ics = [
    'BEGIN:VCALENDAR',
    'VERSION:2.0',
    'PRODID:-//Little Island//Events//EN',
    'BEGIN:VEVENT',
    `UID:${event.slug}@littleisland.cz`,
    `DTSTAMP:${formatIcsDate(new Date())}`,
    `DTSTART:${formatIcsDate(event.startsAt)}`,
    `DTEND:${formatIcsDate(event.endsAt)}`,
    `SUMMARY:${escape(event.title)}`,
    `DESCRIPTION:${escape(event.description)}`,
    `LOCATION:Little Island Pub, Frýdek-Místek`,
    'END:VEVENT',
    'END:VCALENDAR',
  ].join('\r\n');
 
  return new Response(ics, {
    headers: {
      'Content-Type': 'text/calendar; charset=utf-8',
      'Content-Disposition': `attachment; filename="${event.slug}.ics"`,
    },
  });
}

A small touch, but users actually use it (~12 % of clicks on an event go to Add to calendar).

SEO play

Targeting local search:

KWMonthly volumePosition T+30
irish pub frydek mistek110#1
guinness frydek70#1
whiskey bar ostrava320#6 (not local, Ostrava competition)
live music frydek90#2
firemní akce restaurace frydek40#1

Critical: Restaurant + LocalBusiness structured data, Google Maps embed, consistent NAP (name-address-phone) on the site and Google Business Profile. Without that, local Google won't surface you.

Lessons

  • A client with no time for content updates = static-first design. No CMS dashboard, MDX commits via Vercel deploy. When they need to add a whiskey, they message me, I open a PR in 2 minutes.
  • Brand language in CSS is a sales tool. The "describe the first impression" test caught 5 of 5 people with "Irish pub" - higher ROI than SEO copy.
  • Manual booking is a feature, not a bug. Private events need conversation, not a calendar. The form is a friction filter for low-quality leads.
  • ICS export is a fridge magnet. 30 lines of code, 12 % of users use it, the rest see it and read it as "this pub has a polished site".
  • Restaurant structured data > generic Page. Without it, Google Maps won't slot you into local results.