Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Project Overview

**Code Sync** = Framer plugin + CLI to upload/export `.tsx` between local FS and Framer.

- **Plugin** (`src/`): React app inside Framer
- **CLI** (`cli/`): Push files via `framer-api`

## Commands

Plugin:
- `pnpm dev` dev server (https, mkcert)
- `pnpm build` prod build
- `pnpm lint`

CLI (global):
- `framer-code-sync-cli push` push changed
- `framer-code-sync-cli push --force` push all
- `framer-code-sync-cli push --yes` skip confirm
- `framer-code-sync-cli push --refresh` refresh Framer file cache

CLI dev (from `cli/`):
- `pnpm build` compile to dist/
- `pnpm link --global` link globally

## Architecture

### Plugin (`src/`)
- `App.tsx` tabs: Upload / Export / Docs
- `pages/upload` drag-drop upload + transforms
- `pages/export` export Framer code zip
- `pages/docs` docs

Upload flow (`pages/upload/lib`):
1. load config (`config-loader`)
2. read files + paths (`file-processing`)
3. string/import transforms (`string-transforms`)
4. upload: placeholder → real content (`upload-logic`)

Types (`types.ts`):
- `CodeSyncConfig`
- `ImportReplacementRule`, `StringReplacementRule`
- `UploadState`

### CLI (`cli/`)
- `index.ts` entry point, command router
- `push.ts` exports `runPush()`, args `--force`, `--yes`, `--refresh`, `--env`
- `lib/file-scanner` tsx scan from cwd + mtime filter + Framer file cache
- `lib/transform` load config from cwd + apply rules
- `lib/framer-push` upload via API
- Environment-specific `.env` files: `.env` (dev), `.env.staging`, `.env.production`
- Environment-specific cache in `.framer-code-sync-cli/`: `.framer-files.json` (dev), `.framer-files.json.{env}` (others)
- Default environment: `development`
- Caches Framer file structure per environment to avoid API calls (uses cache by default, `--refresh` forces refetch)
Globally installable via `npm i -g framer-code-sync-cli`.

## Config

`framer-code-sync.config.json` at upload root:
- `version`
- `importReplacements`
- `stringReplacements`
- `ignoredFiles`

## Code Style

- Tailwind only, no CSS files
- Handlers: `handleClick`, `handleKeyDown`
- Early returns
- Use `framer-plugin` SDK
38 changes: 38 additions & 0 deletions .cursor/rules/framer-plugin.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
globs: src/*
alwaysApply: false
---
You are a Senior Front-End Developer and an Expert in ReactJS, TypeScript, HTML, CSS and TailwindCSS. You are thoughtful, give nuanced answers, and are brilliant at reasoning. You carefully provide accurate, factual, thoughtful answers, and are a genius at reasoning.

- Follow the user’s requirements carefully & to the letter.
- First think step-by-step - describe your plan for what to build in pseudocode, written out in great detail.
- Confirm, then write code!
- Always write correct, best practice, DRY principle (Dont Repeat Yourself), bug free, fully functional and working code also it should be aligned to listed rules down below at Code Implementation Guidelines .
- Focus on easy and readability code, over being performant.
- Fully implement all requested functionality.
- Leave NO todo’s, placeholders or missing pieces.
- Ensure code is complete! Verify thoroughly finalised.
- Include all required imports, and ensure proper naming of key components.
- Be concise Minimize any other prose.
- If you think there might not be a correct answer, you say so.
- If you do not know the answer, say so, instead of guessing.

### Coding Environment

The user asks questions about the following coding languages:

- ReactJS
- TypeScript
- TailwindCSS
- HTML
- CSS
- Framer Plugin

### Code Implementation Guidelines

Follow these rules when you write code:

- Use early returns whenever possible to make the code more readable.
- Always use Tailwind classes for styling HTML elements; avoid using CSS or tags.
- Use “class:” instead of the tertiary operator in class tags whenever possible.
- Use descriptive variable and function/const names. Also, event functions should be named with a “handle” prefix, like “handleClick” for onClick and “handleKeyDown” for onKeyDown.
74 changes: 74 additions & 0 deletions .cursor/rules/project-overview.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
alwaysApply: true
---
# Project Overview

**Code Sync** = Framer plugin + CLI to upload/export `.tsx` between local FS and Framer.

- **Plugin** (`src/`): React app inside Framer
- **CLI** (`cli/`): Push files via `framer-api`

## Commands

Plugin:
- `pnpm dev` dev server (https, mkcert)
- `pnpm build` prod build
- `pnpm lint`

CLI (global):
- `framer-code-sync-cli push` push changed (default: development env)
- `framer-code-sync-cli push --force` push all
- `framer-code-sync-cli push --yes` skip confirm
- `framer-code-sync-cli push --refresh` refresh Framer file cache
- `framer-code-sync-cli push --env {development|staging|production}` set environment

CLI dev (from `cli/`):
- `pnpm build` compile to dist/
- `pnpm link --global` link globally

## Architecture

### Plugin (`src/`)
- `App.tsx` tabs: Upload / Export / Docs
- `pages/upload` drag-drop upload + transforms
- `pages/export` export Framer code zip
- `pages/docs` docs

Upload flow (`pages/upload/lib`):
1. load config (`config-loader`)
2. read files + paths (`file-processing`)
3. string/import transforms (`string-transforms`)
4. upload: placeholder → real content (`upload-logic`)

Types (`types.ts`):
- `CodeSyncConfig`
- `ImportReplacementRule`, `StringReplacementRule`
- `UploadState`

### CLI (`cli/`)
- `index.ts` entry point, command router
- `push.ts` exports `runPush()`, args `--force`, `--yes`, `--refresh`, `--env`
- `lib/file-scanner` tsx scan from cwd + mtime filter + Framer file cache
- `lib/transform` load config from cwd + apply rules
- `lib/framer-push` upload via API
- Environment-specific `.env` files: `.env` (dev), `.env.staging`, `.env.production`
- Environment-specific cache in `.framer-code-sync-cli/`: `.framer-files.json` (dev), `.framer-files.json.{env}` (others)
- Default environment: `development`
- Caches Framer file structure per environment to avoid API calls (uses cache by default, `--refresh` forces refetch)

Globally installable via `npm i -g framer-code-sync-cli`.

## Config

`framer-code-sync.config.json` at upload root:
- `version`
- `importReplacements`
- `stringReplacements`
- `ignoredFiles`

## Code Style

- Tailwind only, no CSS files
- Handlers: `handleClick`, `handleKeyDown`
- Early returns
- Use `framer-plugin` SDK
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ yarn-error.log\*

plugin.zip

.cursor
/comps
/comps
.env
.framer-push-time
.framer-files.json
112 changes: 109 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ This Framer plugin is built as a modern React application with the following tec
- **CSS Styling** - Combination of inline styles and external `App.css` file. Planning to migrate to Tailwind CSS in the future.
- **ESLint** - Code linting and quality assurance

## 🤖 AI Agentic Coding Support

This repository includes `.cursor` and `.claude` folders with rules and context specifically designed to enhance AI agentic coding experiences. These folders contain:

- **`.cursor/rules/`** - Cursor IDE rules for improved AI-assisted development
- **`.claude/`** - Claude Code AI context and instructions for better code understanding

These files provide AI agents with project-specific knowledge, coding standards, and development workflows to ensure consistent and high-quality contributions.

## ⚡ Quick Start

1. **Select your upload mode** — folder or individual files
Expand Down Expand Up @@ -75,12 +84,12 @@ The plugin merges UI settings with your config, giving **priority to the config
"version": 1,
"importReplacements": [
{ "find": "@stripe/stripe-js", "replace": "./Bundles/Stripe_bundle.tsx" },
{ "find": "./mock/helpers", "replace": "https://example.com/helpers.js" }
{ "find": "./mock/helpers", "replace": "https://example.com/helpers.js" },
],
"ignoredFiles": ["./internal/mock.tsx"],
"stringReplacements": [
{ "find": "(api.tasks.get)", "replace": "(\"tasks:get\")" }
]
{ "find": "(api.tasks.get)", "replace": "(\"tasks:get\")" },
],
}
```

Expand Down Expand Up @@ -126,6 +135,103 @@ Your selected environment is stored per project via `framer.setPluginData`, so c
- `Config not applied` — Ensure `framer-code-sync.config.json` is at the root of your uploaded folder
- `Import errors` — Verify that replacement URLs and paths are correct

## 💻 CLI

Push `.tsx` files to Framer from the command line — no plugin UI needed.

### Installation

**From source (current):**

```bash
git clone https://github.com/david-mcbacon/code-sync-framer-plugin.git
cd framer-code-sync/cli
pnpm install && pnpm build

# Link globally (first time may need: pnpm setup && restart terminal)
pnpm link --global
```

**From npm (once published):**

```bash
npm i -g framer-code-sync-cli
```

### Setup

Create environment-specific `.env` files in your project root:

```env
# .env (for development - default)
FRAMER_PROJECT_URL=https://framer.com/projects/YOUR-PROJECT-ID
FRAMER_API_KEY=YOUR-API-KEY=YOUR-API-SECRET

# .env.staging (for staging)
FRAMER_PROJECT_URL=https://framer.com/projects/YOUR-STAGING-PROJECT-ID
FRAMER_API_KEY=YOUR-API-KEY=YOUR-API-SECRET

# .env.production (for production)
FRAMER_PROJECT_URL=https://framer.com/projects/YOUR-PROD-PROJECT-ID
FRAMER_API_KEY=YOUR-API-KEY=YOUR-API-SECRET
```

The CLI will automatically load the correct `.env` file based on the `--env` flag. If the required `.env` file doesn't exist, it will throw an error.

Optionally add `framer-code-sync.config.json` for transforms (same format as plugin config).

### Usage

```bash
framer-code-sync-cli push # push changed .tsx files (uses development env by default)
framer-code-sync-cli push --force # push all files
framer-code-sync-cli push --yes # skip confirmation
framer-code-sync-cli push --refresh # force refresh of Framer file cache
framer-code-sync-cli push --env development # use development environment (default)
framer-code-sync-cli push --env staging # use staging environment
framer-code-sync-cli push --env production # use production environment

framer-code-sync-cli list # list all files in the Framer project
framer-code-sync-cli list --env staging # list files for a specific environment

framer-code-sync-cli get <file-path> # output the source code of a Framer file to stdout
framer-code-sync-cli get <file-path> --env staging

framer-code-sync-cli insert-url <file-path> # output insertURL(s) for all component exports in a file
framer-code-sync-cli insert-url <file-path> --env staging

framer-code-sync-cli --help # show help
```

### How it works

1. Loads environment-specific `.env` file (`.env`, `.env.staging`, or `.env.production`) based on `--env` flag
2. Scans all `.tsx` files in current directory (recursive)
3. Filters to only changed files since last push (stored in `.framer-code-sync-cli/.framer-push-time` or `.framer-code-sync-cli/.framer-push-time.{env}`)
4. Checks which files exist in Framer:
- Uses cached file structure from `.framer-code-sync-cli/.framer-files.json` (default, faster)
- Environment-specific cache files: `.framer-code-sync-cli/.framer-files.json.{env}` for staging/production
- Fetches from Framer API if cache missing or `--refresh` flag used
5. Applies transforms from config (if present)
6. Replaces `ENV.tsx` variables based on selected environment (defaults to `development`)
- Replaces `ENV.*.development` → `ENV.*.{selected}` (e.g., `ENV.API_URL.development` → `ENV.API_URL.staging`)
7. Pushes to Framer via `framer-api`
8. Updates cache with newly created files

### File Caching

The CLI caches Framer's file structure and push timestamps in `.framer-code-sync-cli/` folder to avoid API calls on every push. Each environment has separate cache files:

- **Development** (default): `.framer-code-sync-cli/.framer-files.json` and `.framer-code-sync-cli/.framer-push-time`
- **Staging**: `.framer-code-sync-cli/.framer-files.json.staging` and `.framer-code-sync-cli/.framer-push-time.staging`
- **Production**: `.framer-code-sync-cli/.framer-files.json.production` and `.framer-code-sync-cli/.framer-push-time.production`

- **First run**: Fetches from Framer and creates cache
- **Subsequent runs**: Uses cache by default (much faster)
- **Refresh cache**: Use `--refresh` or `--refetch` to force refetch from Framer
- **Auto-update**: Cache is automatically updated with newly created files after each push
- **Environment isolation**: Each environment maintains its own cache, so push times and file lists are tracked separately

## 🤝 Contributing

Every developer’s needs are different — that’s why this plugin is open source.
Expand Down
3 changes: 3 additions & 0 deletions cli-example-folder-push/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Get this from your Framer project settings
FRAMER_PROJECT_URL=https://framer.com/projects/Your-Project--xxxxxxxxxxxxxx
FRAMER_API_KEY=xxx
7 changes: 7 additions & 0 deletions cli-example-folder-push/Comp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

export default function Comp() {
return (
<div>Comp</div>
)
}
7 changes: 7 additions & 0 deletions cli-example-folder-push/Comp2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

export default function Comp2() {
return (
<div>Comp2</div>
)
}
5 changes: 5 additions & 0 deletions cli/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.env
last-push.txt
.framer-push-time
node_modules/
/dist
Loading