Skip to content

Commit b13e901

Browse files
committed
feat: add iconlogo tool codebase
1 parent ac45583 commit b13e901

110 files changed

Lines changed: 20174 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"mcp__ide__getDiagnostics"
5+
]
6+
}
7+
}

iconlogo/.cta.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"projectName": "web",
3+
"mode": "file-router",
4+
"typescript": true,
5+
"packageManager": "bun",
6+
"includeExamples": false,
7+
"tailwind": true,
8+
"addOnOptions": {},
9+
"envVarValues": {},
10+
"git": true,
11+
"routerOnly": false,
12+
"version": 1,
13+
"framework": "react",
14+
"chosenAddOns": [
15+
"biome",
16+
"tanstack-query"
17+
]
18+
}

iconlogo/.github/FUNDING.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# These are supported funding model platforms
2+
3+
github: mxvsh
4+
patreon: # Replace with a single Patreon username
5+
open_collective: # Replace with a single Open Collective username
6+
ko_fi: monawwar
7+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9+
liberapay: # Replace with a single Liberapay username
10+
issuehunt: # Replace with a single IssueHunt username
11+
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12+
polar: # Replace with a single Polar username
13+
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14+
thanks_dev: # Replace with a single thanks.dev username
15+
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

iconlogo/.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# dependencies
2+
/node_modules
3+
4+
# testing
5+
/coverage
6+
7+
# production
8+
/build
9+
/dist
10+
11+
# misc
12+
.DS_Store
13+
*.pem
14+
15+
# debug
16+
npm-debug.log*
17+
18+
# env files (can opt-in for committing if needed)
19+
.env
20+
.env.local
21+
22+
# typescript
23+
*.tsbuildinfo
24+
25+
# cloudflare
26+
.wrangler
27+
.dev.vars

iconlogo/.vscode/settings.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"files.watcherExclude": {
3+
"**/routeTree.gen.ts": true
4+
},
5+
"search.exclude": {
6+
"**/routeTree.gen.ts": true
7+
},
8+
"files.readonlyInclude": {
9+
"**/routeTree.gen.ts": true
10+
},
11+
"[javascript]": {
12+
"editor.defaultFormatter": "biomejs.biome"
13+
},
14+
"[javascriptreact]": {
15+
"editor.defaultFormatter": "biomejs.biome"
16+
},
17+
"[typescript]": {
18+
"editor.defaultFormatter": "biomejs.biome"
19+
},
20+
"[typescriptreact]": {
21+
"editor.defaultFormatter": "biomejs.biome"
22+
},
23+
"[json]": {
24+
"editor.defaultFormatter": "biomejs.biome"
25+
},
26+
"[jsonc]": {
27+
"editor.defaultFormatter": "biomejs.biome"
28+
},
29+
"[css]": {
30+
"editor.defaultFormatter": "biomejs.biome"
31+
},
32+
"editor.codeActionsOnSave": {
33+
"source.organizeImports.biome": "explicit"
34+
}
35+
}

iconlogo/AGENTS.md

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# IconLogo.dev — Codex Guidelines
2+
3+
## Stack
4+
5+
- **Runtime**: Cloudflare Workers (via Wrangler)
6+
- **Framework**: Vite + TanStack Start (file-based routing)
7+
- **UI**: HeroUI v3.0.0-beta.8 (compound component API), Tailwind CSS
8+
- **State**: Zustand with immer
9+
- **Data fetching**: TanStack Query
10+
- **Icons**: @iconify/react
11+
- **Animations**: Framer Motion
12+
- **Package manager**: Bun
13+
14+
---
15+
16+
## Architecture: CQRS + Domain-Driven
17+
18+
The codebase is organized into strict layers. **Import direction is one-way — never import upward.**
19+
20+
```
21+
routes → features → commands → store → domain
22+
↘ queries → infra → domain
23+
server → infra → domain
24+
```
25+
26+
### Layer Rules
27+
28+
| Layer | Location | Rule |
29+
|---|---|---|
30+
| **domain** | `src/domain/` | Pure TypeScript. Zero framework or runtime deps. No React, no Zustand, no fetch. Fully unit-testable. |
31+
| **infra** | `src/infra/` | Adapters for external APIs and browser APIs (fetch, canvas, clipboard, KV). No React. |
32+
| **store** | `src/store/` | Zustand stores only. Imports from domain and infra. Never imported by domain or infra. |
33+
| **commands** | `src/commands/` | Plain async functions (not hooks). Call `useStore.getState()` for reads/writes. Callable from event handlers, other commands, keyboard shortcuts. |
34+
| **queries** | `src/queries/` | React hooks only. Zustand selectors for local state, TanStack Query for remote data. Read-only — no mutations. |
35+
| **features** | `src/features/` | React components organized by feature. Import commands and queries. Never import from store or infra directly. |
36+
| **routes** | `src/routes/` | TanStack Router file routes. Orchestrate features. Handle URL params and loaders. |
37+
| **server** | `src/server/` | TanStack Start server functions (`createServerFn`). Run on Cloudflare Worker. Access KV via `import { env } from 'cloudflare:workers'`. |
38+
| **data** | `src/data/` | Static app content (changelog, constants, copy). No logic, no imports from other layers. Plain TypeScript arrays/objects. |
39+
40+
---
41+
42+
## Strict Rules
43+
44+
### 1. Components never touch the store or infra directly
45+
Features import from `commands/` and `queries/` only. If a component needs to mutate state, there must be a command function for it.
46+
47+
```ts
48+
// WRONG — component calling store directly
49+
const set = useLogoStore((s) => s.set);
50+
set((d) => { d.iconName = "lucide:heart"; });
51+
52+
// RIGHT — component calls a command
53+
import { updateLogo } from "#/commands/logo/update-logo";
54+
updateLogo((d) => { d.iconName = "lucide:heart"; });
55+
```
56+
57+
### 2. Commands are plain functions, not hooks
58+
Commands must be callable outside React (from other commands, keyboard shortcuts, etc.).
59+
60+
```ts
61+
// WRONG
62+
export function useUpdateLogo() { ... }
63+
64+
// RIGHT
65+
export function updateLogo(updater: (d: LogoState) => void) { ... }
66+
```
67+
68+
### 3. Domain logic has zero dependencies
69+
`src/domain/` files must not import from React, Zustand, TanStack, or any external package. Pure TypeScript functions and types only.
70+
71+
### 4. Queries are read-only hooks
72+
Hooks in `src/queries/` must not call commands or mutate state. They return data only.
73+
74+
### 5. Server functions use `cloudflare:workers` env
75+
Access Cloudflare bindings via `import { env } from 'cloudflare:workers'`. Never use `globalThis.env` or `process.env` for KV/D1/R2.
76+
77+
```ts
78+
// WRONG
79+
const kv = (globalThis as any).env.SHARE_KV;
80+
81+
// RIGHT
82+
import { env } from "cloudflare:workers";
83+
const kv = (env as { SHARE_KV?: KVNamespace }).SHARE_KV;
84+
```
85+
86+
### 6. Use the `#/` path alias
87+
Always use `#/` for src-relative imports. Never use relative `../../` paths crossing more than one directory.
88+
89+
```ts
90+
// WRONG
91+
import { updateLogo } from "../../commands/logo/update-logo";
92+
93+
// RIGHT
94+
import { updateLogo } from "#/commands/logo/update-logo";
95+
```
96+
97+
### 7. HeroUI compound component API
98+
This project uses HeroUI v3.0.0-beta.8. Use the compound API — dot notation for sub-components.
99+
100+
```tsx
101+
// WRONG (HeroUI v2 API)
102+
<ModalHeader>...</ModalHeader>
103+
104+
// RIGHT (HeroUI v3 compound API)
105+
<Modal.Header>...</Modal.Header>
106+
<Select.Trigger>...</Select.Trigger>
107+
<Tabs.Panel id="...">...</Tabs.Panel>
108+
```
109+
110+
### 8. No `"use client"` directives
111+
This is a Vite app, not Next.js. Never add `"use client"` to any file.
112+
113+
### 9. Avoid over-engineering
114+
- Don't create helpers for one-off operations
115+
- Don't add error handling for scenarios that can't happen
116+
- Don't add comments unless the logic is non-obvious
117+
- Don't add types for things TypeScript already infers
118+
- Three similar lines > a premature abstraction
119+
120+
---
121+
122+
## File Naming Conventions
123+
124+
- **Domain types/logic**: `<noun>.<kind>.ts` — e.g. `logo.types.ts`, `logo.validators.ts`
125+
- **Commands**: `<verb>-<noun>.ts` — e.g. `update-logo.ts`, `randomize-logo.ts`
126+
- **Queries**: `use-<noun>.ts` — e.g. `use-logo-state.ts`, `use-icon-search.ts`
127+
- **Infra**: `<noun>-client.ts` or `<noun>.ts` — e.g. `iconify-client.ts`, `canvas-renderer.ts`
128+
- **Components**: `PascalCase.tsx` — e.g. `IconPickerModal.tsx`, `LogoCanvas.tsx`
129+
- **Server functions**: `<resource>.<action>.ts` — e.g. `share.create.ts`, `share.get.ts`
130+
131+
---
132+
133+
## Dev Commands
134+
135+
```bash
136+
bun run dev # Start dev server
137+
bun run build # Vite build
138+
bun run typecheck # tsc --noEmit
139+
bun run lint # Biome lint
140+
bun run deploy # Deploy to Cloudflare Workers
141+
```
142+
143+
---
144+
145+
## Key Domain Types
146+
147+
- `LogoState` — the full editor state (`src/domain/logo/logo.types.ts`)
148+
- `Background` — solid or gradient (`src/domain/logo/logo.types.ts`)
149+
- `ICON_SETS` — array of `{ id, label }` for all supported icon sets (`src/domain/icon/icon.types.ts`)
150+
- `IconSvgCache` — cached SVG strings and data URIs (`src/domain/icon/icon.types.ts`)
151+
- `CollectionItem` — saved logo with id and timestamp (`src/domain/collection/collection.types.ts`)
152+
153+
---
154+
155+
## Cloudflare KV
156+
157+
- Binding name: `SHARE_KV`
158+
- Key pattern: `share:<nanoid6>`
159+
- TTL: 30 days
160+
- Configured in `wrangler.jsonc` under `kv_namespaces`
161+
- Real KV namespace ID must be a 32-char hex string (set before deploying)

0 commit comments

Comments
 (0)