---
name: vewr-file-generator
description: >
  Generate interactive JSX files for the Vewr app — a local mobile + desktop file viewer.
  Use this skill whenever a user asks to build anything for Vewr: dashboards, trackers,
  planners, habit apps, reports, calculators, or any interactive UI. Trigger even if the
  user just says "make a JSX file", "build something for Vewr", "create a Vewr component",
  or "I want a file I can open in Vewr". Always use this skill when the word "Vewr" appears
  in the request, regardless of how simple the ask seems.
---

# Vewr File Generator

Generate self-contained `.jsx` files that open correctly in the Vewr app. Vewr renders
React components locally — no server, no account. Files must be fully standalone.

---

## Before Writing Any Code

If the user hasn't specified a screen size, ask:

> "Will this be viewed on a **phone** or a **larger screen** (tablet / desktop)?"

If they say both, default to **phone** and use Tailwind responsive prefixes (`md:`, `lg:`)
to enhance at larger sizes. If the context makes it obvious (e.g. "mobile habit tracker"),
skip the question and proceed.

---

## Required File Structure

Every file must follow this exact pattern:

```jsx
import { useState, useEffect } from 'react'     // only hooks you actually use
import { IconName } from 'lucide-react'          // only if icons are needed
import { LineChart, Line } from 'recharts'       // only if charts are needed

export default function ComponentName() {
  // state and logic here
  return (
    <div className="...">
      {/* content */}
    </div>
  )
}
```

**Hard rules:**
- `export default function ComponentName()` — required export pattern, capital letter name
- Imports only from `react`, `lucide-react`, or `recharts` — nothing else
- No `ReactDOM.render` or `createRoot` — Vewr mounts the component automatically
- No `document.*`, `window.*`, or `navigator.*` — runs inside a sandboxed iframe
- No network calls (no `fetch`, `axios`, etc.) — Vewr is fully offline
- No `require()` — ESM imports only
- No `process.env` or Node globals
- All data lives inside the component via `useState` — no props, no external sources

---

## Available Libraries

| Library | Version | Import |
|---|---|---|
| React 18 | — | `import { useState } from 'react'` |
| Tailwind CSS | CDN | utility classes, all work |
| lucide-react | 0.383.0 | `import { Flame } from 'lucide-react'` |
| recharts | 2.12.7 | `import { LineChart } from 'recharts'` |
| framer-motion | 11.0.3 | `import { motion } from 'framer-motion'` |
| dayjs | 1.11.10 | `import dayjs from 'dayjs'` |
| clsx | — | `import clsx from 'clsx'` |
| tailwind-merge | — | `import { twMerge } from 'tailwind-merge'` |

Everything else is unavailable. Use `dayjs` instead of `date-fns`. Use Tailwind instead of
`styled-components`.

---

## Phone Layout Guidelines

Apply when target is phone (or unknown):

- **Font sizes:** `text-base` (16px) minimum for body. `text-lg`/`text-xl` for labels. Headlines `text-2xl`–`text-4xl`.
- **Touch targets:** `py-3 px-6` minimum for buttons. `p-3` minimum for icon-only buttons. `py-4` per list row.
- **Layout:** Single column. `w-full` for cards and buttons. No horizontal scrolling.
- **Spacing:** `gap-4`, `p-4` or `p-6` for cards. `mb-6` between sections.
- **Charts:** `w-full` with fixed height. Always use `<ResponsiveContainer width="100%" height={200}>`.
- **Avoid:** `text-xs`/`text-sm` as primary size, multi-column grids without `md:` prefix, dense tables.

## Desktop / Tablet Layout Guidelines

Apply when target is tablet or desktop:

- **Layout:** `max-w-4xl mx-auto` or `max-w-6xl mx-auto`. Multi-column grids (`grid-cols-2`, `grid-cols-3`) are fine.
- **Font sizes:** `text-sm` acceptable for secondary text. `text-base` for body.
- **Touch targets:** Standard `py-2 px-4`.
- **Charts:** Fixed larger heights (`h-64`, `h-80`).
- **Tables:** Dense tables are fine.

---

## Common Patterns

### Tabs

```jsx
const [tab, setTab] = useState('overview')
const tabs = ['overview', 'history', 'settings']

<div className="flex gap-2 mb-6">
  {tabs.map(t => (
    <button
      key={t}
      onClick={() => setTab(t)}
      className={`flex-1 py-3 rounded-full text-sm font-semibold capitalize transition-colors
        ${tab === t ? 'bg-gray-900 text-white' : 'bg-gray-100 text-gray-600'}`}
    >
      {t}
    </button>
  ))}
</div>
```

### Chart (phone)

```jsx
import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts'

const data = [{ day: 'Mon', value: 4 }, { day: 'Tue', value: 7 }]

<ResponsiveContainer width="100%" height={200}>
  <LineChart data={data}>
    <XAxis dataKey="day" />
    <YAxis />
    <Tooltip />
    <Line type="monotone" dataKey="value" stroke="#4e6073" strokeWidth={2} dot={false} />
  </LineChart>
</ResponsiveContainer>
```

### List with add/remove

```jsx
const [items, setItems] = useState(['Item one', 'Item two'])
const [input, setInput] = useState('')

function add() {
  if (!input.trim()) return
  setItems(prev => [...prev, input.trim()])
  setInput('')
}

function remove(i) {
  setItems(prev => prev.filter((_, idx) => idx !== i))
}
```

---

## Output Checklist

Before delivering the file, verify:

- [ ] Asked about screen size (or inferred it from context)
- [ ] Imports only from `react`, `lucide-react`, `recharts`, `framer-motion`, `dayjs`, `clsx`, or `tailwind-merge`
- [ ] `export default function ComponentName()` — capital letter, no separate mount call
- [ ] No `fetch`, `axios`, or any network call
- [ ] No `document.*` / `window.*` / `navigator.*`
- [ ] All data self-contained in `useState`
- [ ] Touch targets meet the size guidelines for the target screen
- [ ] Charts wrapped in `<ResponsiveContainer>` on phone

## Delivering the File

Save the output as a `.jsx` file (e.g. `HabitTracker.jsx`). The user opens it directly in Vewr — no build step needed.
