Stack overview
EmailingSimply is built with:
- Nuxt 3 (Nuxt 4 compatibility mode) — the frontend framework
- Nuxt Content v2 — content management via Markdown files in
/content - Firebase — authentication (Firebase Auth) and user data storage (Firestore)
- Tailwind CSS — utility-first styling via PostCSS
- Vercel — hosting and deployment
The source code lives in /app (Nuxt 4 app/ directory structure). Content lives in /content.
How components are defined
Each email component is a Markdown file in content/components/. The frontmatter defines all metadata; the html field contains the raw email HTML.
---
title: My Component
slug: my-component
description: What this component does
category: Hero
tags: [hero, cta]
premium: false
featured: false
darkModeSupport: partial # none | partial | full
mobileSupport: full # none | partial | full
outlookSupport: full # none | partial | full
compatibility:
gmailWeb: full
gmailIos: full
gmailAndroid: full
appleMail: full
appleMailIos: partial
outlookWindows: full
outlookMac: full
outlookCom: full
yahooMail: full
createdAt: "2025-08-01"
updatedAt: "2025-08-01"
html: |
<table role="presentation" ...>
...
</table>
---
Optional markdown notes about the component go here.
Token system
The HTML uses {{ tokenName }} placeholders that are replaced client-side by the customizer. Available tokens are defined in app/composables/useEmailCustomizer.ts:
| Token | Default | Purpose |
|---|---|---|
background | #f5f5f5 | Outer wrapper background |
contentBg | #ffffff | Content area background |
textColor | #1a1a1a | Body text color |
accent | #2563eb | Accent / highlight color |
buttonColor | #2563eb | CTA button background |
buttonTextColor | #ffffff | CTA button text |
borderColor | #e5e5e5 | Borders and dividers |
borderRadius | 4px | Border radius on cards/buttons |
fontFamily | Arial, Helvetica, sans-serif | Font stack |
heading | Your Heading Here | Heading text placeholder |
body | (placeholder) | Body copy placeholder |
ctaText | Shop Now | CTA button label |
ctaUrl | https://example.com | CTA button URL |
spacing | 24px | Vertical padding |
Variants
A component can have multiple variants (e.g. Default, Dark background, Image background). Each variant needs a slug and can optionally include its own html:
variants:
- name: Dark background
slug: dark
description: Dark version for dark-themed emails
html: |
<table ...>
<!-- dark variant HTML -->
</table>
If a variant has no html, clicking its tab shows the default HTML.
How guides and articles are defined
Guides live in content/guides/, articles in content/articles/. Both use Markdown with frontmatter:
---
title: Guide title
slug: guide-slug
description: Short description
difficulty: beginner # beginner | intermediate | advanced
publishedAt: "2025-08-01"
tags: [tag1, tag2]
---
Guide content in Markdown...
Nuxt Content renders these with the ContentRenderer component, which uses Shiki for syntax highlighting.
Deployment
The app deploys automatically to Vercel on push to main. Environment variables for Firebase are set in Vercel project settings and injected via nuxt.config.ts runtimeConfig.public.
Firestore security rules must be updated separately in the Firebase Console.