@vibes.diy/prompts 0.20.3-dev-push → 0.20.5-dev-cli-stable-entry
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build-schema-prompt.d.ts +1 -0
- package/build-schema-prompt.js +18 -0
- package/build-schema-prompt.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/llms/callai.js +0 -1
- package/llms/callai.js.map +1 -1
- package/llms/callai.md +76 -0
- package/llms/d3.md +11 -0
- package/llms/fireproof.js +0 -1
- package/llms/fireproof.js.map +1 -1
- package/llms/{fireproof.txt → fireproof.md} +116 -69
- package/llms/image-gen.js +0 -1
- package/llms/image-gen.js.map +1 -1
- package/llms/{image-gen.txt → image-gen.md} +14 -15
- package/llms/three-js.md +10 -0
- package/llms/types.d.ts +0 -1
- package/llms/{web-audio.txt → web-audio.md} +25 -15
- package/package.json +16 -8
- package/prompts.d.ts +2 -10
- package/prompts.js +26 -18
- package/prompts.js.map +1 -1
- package/llms/callai.txt +0 -352
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function buildSchemaSystemMessage(schema: object): Promise<string>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { generate } from "json-schema-faker";
|
|
2
|
+
async function buildExample(schema) {
|
|
3
|
+
const result = await generate(schema, { optionalsProbability: 1 });
|
|
4
|
+
if (!result) {
|
|
5
|
+
return {};
|
|
6
|
+
}
|
|
7
|
+
return result;
|
|
8
|
+
}
|
|
9
|
+
export async function buildSchemaSystemMessage(schema) {
|
|
10
|
+
const example = await buildExample(schema);
|
|
11
|
+
return `Return ONLY a JSON object inside a \`\`\`json code fence. Conform to this schema: ${JSON.stringify(schema)}
|
|
12
|
+
|
|
13
|
+
Example of expected output:
|
|
14
|
+
\`\`\`json
|
|
15
|
+
${JSON.stringify(example, null, 2)}
|
|
16
|
+
\`\`\``;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=build-schema-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-schema-prompt.js","sourceRoot":"","sources":["../jsr/build-schema-prompt.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,QAAQ,EAAmB,MAAM,mBAAmB,CAAC;AAE9D,KAAK,UAAU,YAAY,CAAC,MAAkB;IAC5C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,oBAAoB,EAAE,CAAC,EAAE,CAAC,CAAC;IACnE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,MAAc;IAC3D,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAoB,CAAC,CAAC;IACzD,OAAO,qFAAqF,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;;;;EAIlH,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;OAC3B,CAAC;AACR,CAAC"}
|
package/index.d.ts
CHANGED
|
@@ -7,3 +7,4 @@ export * from "./style-prompts.js";
|
|
|
7
7
|
export { parseContent } from "./segment-parser.js";
|
|
8
8
|
export { resolveEffectiveModel } from "./prompts.js";
|
|
9
9
|
export { normalizeComponentExports, transformImports, coreImportMap } from "./component-transforms.js";
|
|
10
|
+
export { buildSchemaSystemMessage } from "./build-schema-prompt.js";
|
package/index.js
CHANGED
|
@@ -7,4 +7,5 @@ export * from "./style-prompts.js";
|
|
|
7
7
|
export { parseContent } from "./segment-parser.js";
|
|
8
8
|
export { resolveEffectiveModel } from "./prompts.js";
|
|
9
9
|
export { normalizeComponentExports, transformImports, coreImportMap } from "./component-transforms.js";
|
|
10
|
+
export { buildSchemaSystemMessage } from "./build-schema-prompt.js";
|
|
10
11
|
//# sourceMappingURL=index.js.map
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../jsr/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAE/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGrD,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../jsr/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAE/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGrD,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEvG,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC"}
|
package/llms/callai.js
CHANGED
package/llms/callai.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callai.js","sourceRoot":"","sources":["../../jsr/llms/callai.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,
|
|
1
|
+
{"version":3,"file":"callai.js","sourceRoot":"","sources":["../../jsr/llms/callai.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,YAAY;IACpB,WAAW,EAAE,kDAAkD;IAC/D,YAAY,EAAE,SAAS;IACvB,UAAU,EAAE,QAAQ;CACrB,CAAC"}
|
package/llms/callai.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# CallAI Helper Function
|
|
2
|
+
|
|
3
|
+
The `callAI` function returns structured JSON from an AI model. It always requires a schema and returns a string that you `JSON.parse()`.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
import { callAI } from "call-ai";
|
|
9
|
+
|
|
10
|
+
const response = await callAI("Give me a todo list for learning React", {
|
|
11
|
+
schema: {
|
|
12
|
+
properties: {
|
|
13
|
+
todos: {
|
|
14
|
+
type: "array",
|
|
15
|
+
description: "List of actionable todo items",
|
|
16
|
+
items: { type: "string" },
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
const todoData = JSON.parse(response);
|
|
22
|
+
console.log(todoData.todos);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Items with properties
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
const response = await callAI(
|
|
29
|
+
"Generate 4 items with label, status, priority (low, medium, high, critical), and notes. Return as structured JSON with these fields.",
|
|
30
|
+
{
|
|
31
|
+
schema: {
|
|
32
|
+
properties: {
|
|
33
|
+
items: {
|
|
34
|
+
type: "array",
|
|
35
|
+
items: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
label: { type: "string", description: "Short name for the item" },
|
|
39
|
+
status: { type: "string", description: "Current status (active, done, blocked)" },
|
|
40
|
+
priority: { type: "string", description: "Priority level (low, medium, high, critical)" },
|
|
41
|
+
notes: { type: "string", description: "Additional context or details" },
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
const demoData = JSON.parse(response);
|
|
50
|
+
console.log(demoData.items); // Array of item objects
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Schema Tips
|
|
54
|
+
|
|
55
|
+
- Flat schemas perform better across all models. Avoid nesting deeper than 2 levels.
|
|
56
|
+
- Use simple property names like `name`, `type`, `items`, `price`.
|
|
57
|
+
- Keep array items simple (strings or flat objects).
|
|
58
|
+
|
|
59
|
+
## Error Handling
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
import { callAI } from "call-ai";
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const response = await callAI("Generate some content", {
|
|
66
|
+
schema: {
|
|
67
|
+
properties: {
|
|
68
|
+
result: { type: "string" },
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
console.log(JSON.parse(response));
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error("API error:", error.message);
|
|
75
|
+
}
|
|
76
|
+
```
|
package/llms/d3.md
CHANGED
|
@@ -126,11 +126,22 @@ bars
|
|
|
126
126
|
|
|
127
127
|
## Complete Examples for Coding Agents
|
|
128
128
|
|
|
129
|
+
### Code Structure for D3 + React Apps
|
|
130
|
+
|
|
131
|
+
Structure your component in this order:
|
|
132
|
+
|
|
133
|
+
1. **D3 helper functions** — visualization logic separate from React
|
|
134
|
+
2. **Hooks and state** — useFireproof, useRef, useState
|
|
135
|
+
3. **Effects** — useEffect to call D3 helpers when data changes
|
|
136
|
+
4. **ClassNames object** — colors, dimensions right before JSX so they stay consistent
|
|
137
|
+
5. **JSX return** — layout with refs for D3 to target
|
|
138
|
+
|
|
129
139
|
### 1. Simple Bar Chart
|
|
130
140
|
|
|
131
141
|
```js
|
|
132
142
|
import * as d3 from "d3";
|
|
133
143
|
|
|
144
|
+
// 1. Design tokens and dimensions
|
|
134
145
|
const data = [4, 8, 15, 16, 23, 42];
|
|
135
146
|
const width = 500;
|
|
136
147
|
const height = 300;
|
package/llms/fireproof.js
CHANGED
package/llms/fireproof.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fireproof.js","sourceRoot":"","sources":["../../jsr/llms/fireproof.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,cAAc;IACrB,
|
|
1
|
+
{"version":3,"file":"fireproof.js","sourceRoot":"","sources":["../../jsr/llms/fireproof.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,cAAc;IACrB,MAAM,EAAE,eAAe;IACvB,WAAW,EAAE,+CAA+C;IAC5D,YAAY,EAAE,eAAe;IAC7B,UAAU,EAAE,cAAc;CAC3B,CAAC"}
|
|
@@ -7,7 +7,7 @@ Fireproof is a lightweight embedded document database with encrypted live sync,
|
|
|
7
7
|
- **Apps run anywhere:** Bundle UI, data, and logic in one file.
|
|
8
8
|
- **Real-Time & Offline-First:** Automatic persistence and live queries, runs in the browser - no loading or error states.
|
|
9
9
|
- **Unified API:** TypeScript works with Deno, Bun, Node.js, and the browser.
|
|
10
|
-
- **React Hooks:** Leverage `useLiveQuery` and `useDocument` for live collaboration.
|
|
10
|
+
- **React Hooks:** Leverage `useLiveQuery` and `useDocument` for live collaboration. Note: these are NOT top-level exports — they are returned by the `useFireproof()` hook. Always destructure from `const { useLiveQuery, useDocument, database } = useFireproof("db-name")`.
|
|
11
11
|
|
|
12
12
|
Fireproof enforces cryptographic causal consistency and ledger integrity using hash history, providing git-like versioning with lightweight blockchain-style verification. Data is stored and replicated as content-addressed encrypted blobs, making it safe and easy to sync via commodity object storage providers.
|
|
13
13
|
|
|
@@ -55,25 +55,19 @@ const App = () => {
|
|
|
55
55
|
return (
|
|
56
56
|
<div>
|
|
57
57
|
<form onSubmit={submit}>
|
|
58
|
-
<input
|
|
59
|
-
value={doc.text}
|
|
60
|
-
onChange={(e) => merge({ text: e.target.value })}
|
|
61
|
-
placeholder="New document"
|
|
62
|
-
/>
|
|
58
|
+
<input value={doc.text} onChange={(e) => merge({ text: e.target.value })} placeholder="New document" />
|
|
63
59
|
<button type="submit">Submit</button>
|
|
64
60
|
</form>
|
|
65
61
|
|
|
66
62
|
<h3>Recent Documents</h3>
|
|
67
63
|
<ul>
|
|
68
64
|
{docs.map((doc) => (
|
|
69
|
-
<li key={doc._id}>
|
|
70
|
-
|
|
71
|
-
</li>
|
|
72
|
-
))}
|
|
65
|
+
<li key={doc._id}>{doc.text}</li>
|
|
66
|
+
))}
|
|
73
67
|
</ul>
|
|
74
68
|
</div>
|
|
75
69
|
);
|
|
76
|
-
}
|
|
70
|
+
};
|
|
77
71
|
```
|
|
78
72
|
|
|
79
73
|
### Editing Documents
|
|
@@ -87,18 +81,34 @@ const { doc, merge, submit, save, reset } = useDocument({ _id: "user-profile:abc
|
|
|
87
81
|
```
|
|
88
82
|
|
|
89
83
|
The `useDocument` hook provides several methods:
|
|
84
|
+
|
|
90
85
|
- `merge(updates)`: Update the document with new fields, without saving. Use this instead of keeping a `useState` for document data.
|
|
91
86
|
- `submit(e)`: Handles form submission by preventing default, saving, and resetting
|
|
92
87
|
- `save()`: Save the current document state
|
|
93
88
|
- `reset()`: Reset to initial state
|
|
94
89
|
|
|
95
90
|
For form-based creation flows, use `submit`:
|
|
91
|
+
|
|
96
92
|
```js
|
|
97
93
|
<form onSubmit={submit}>
|
|
98
94
|
```
|
|
99
95
|
|
|
100
96
|
When you call submit, the document is reset, so if you didn't provide an `_id` then you can use the form to create a stream of new documents as in the basic example above.
|
|
101
97
|
|
|
98
|
+
### Updating Documents in Event Handlers
|
|
99
|
+
|
|
100
|
+
To update an existing document from a click handler or callback, use `database.put()` directly. Never call `useDocument` inside an event handler — that violates React's Rules of Hooks.
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
// ✅ Correct — use database.put() in handlers
|
|
104
|
+
onClick={() => database.put({ ...doc, favorite: !doc.favorite })}
|
|
105
|
+
|
|
106
|
+
// ❌ Wrong — never call hooks inside handlers
|
|
107
|
+
function toggleFavorite(id) {
|
|
108
|
+
const { doc, save } = useDocument({ _id: id }) // BREAKS Rules of Hooks
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
102
112
|
### Query Data
|
|
103
113
|
|
|
104
114
|
Data is queried by sorted indexes defined by the application. Sort by strings, numbers, or booleans, as well as arrays for grouping. Use numbers when possible for sorting continuous data.
|
|
@@ -110,16 +120,18 @@ Here are other common patterns:
|
|
|
110
120
|
#### Query by Key Range
|
|
111
121
|
|
|
112
122
|
Passing a string to `useLiveQuery` will index by that field. You can use the key argument to filter by a specific value:
|
|
123
|
+
|
|
113
124
|
```js
|
|
114
|
-
const { docs } = useLiveQuery("agentName", {
|
|
115
|
-
key: "agent-1"
|
|
125
|
+
const { docs } = useLiveQuery("agentName", {
|
|
126
|
+
key: "agent-1", // all docs where doc.agentName === "agent-1", sorted by _id
|
|
116
127
|
});
|
|
117
128
|
```
|
|
118
129
|
|
|
119
130
|
You can also query a range within a key:
|
|
131
|
+
|
|
120
132
|
```js
|
|
121
|
-
const { docs } = useLiveQuery("agentRating", {
|
|
122
|
-
range: [3, 5]
|
|
133
|
+
const { docs } = useLiveQuery("agentRating", {
|
|
134
|
+
range: [3, 5],
|
|
123
135
|
});
|
|
124
136
|
```
|
|
125
137
|
|
|
@@ -127,23 +139,21 @@ const { docs } = useLiveQuery("agentRating", {
|
|
|
127
139
|
|
|
128
140
|
Documents can be updated by multiple clients, and synced later. To create an event counter, don't increment a number on a single doc, instead write a small document per counted event, and query them with an index. Example:
|
|
129
141
|
|
|
130
|
-
|
|
131
142
|
```js
|
|
132
143
|
const App = () => {
|
|
133
144
|
const { useLiveQuery, database } = useFireproof("my-ledger");
|
|
134
145
|
|
|
135
|
-
const { docs } = useLiveQuery(
|
|
136
|
-
const counterValue = docs.length
|
|
146
|
+
const { docs } = useLiveQuery("counter", { key: "my-event-name" });
|
|
147
|
+
const counterValue = docs.length;
|
|
137
148
|
|
|
138
149
|
function countEvent() {
|
|
139
150
|
database.put({
|
|
140
|
-
counter
|
|
141
|
-
})
|
|
151
|
+
counter: "my-event-name",
|
|
152
|
+
});
|
|
142
153
|
}
|
|
143
154
|
|
|
144
155
|
// Call countEvent() to count each event, and render counterValue in the UI.
|
|
145
|
-
|
|
146
|
-
}
|
|
156
|
+
};
|
|
147
157
|
```
|
|
148
158
|
|
|
149
159
|
This pattern ensures the count is accurate even during sync.
|
|
@@ -155,13 +165,14 @@ Use a custom index function to normalize and transform document data, for instan
|
|
|
155
165
|
```js
|
|
156
166
|
const { docs } = useLiveQuery(
|
|
157
167
|
(doc) => {
|
|
158
|
-
if (doc.type ==
|
|
168
|
+
if (doc.type == "listing_v1") {
|
|
159
169
|
return doc.sellerId;
|
|
160
|
-
} else if (doc.type ==
|
|
170
|
+
} else if (doc.type == "listing") {
|
|
161
171
|
return doc.userId;
|
|
162
172
|
}
|
|
163
|
-
},
|
|
164
|
-
{ key
|
|
173
|
+
},
|
|
174
|
+
{ key: routeParams.sellerId }
|
|
175
|
+
);
|
|
165
176
|
```
|
|
166
177
|
|
|
167
178
|
#### Array Indexes and Prefix Queries
|
|
@@ -186,26 +197,23 @@ Sortable lists are a common pattern. Here's how to implement them using Fireproo
|
|
|
186
197
|
```js
|
|
187
198
|
function App() {
|
|
188
199
|
const { database, useLiveQuery } = useFireproof("my-ledger");
|
|
189
|
-
|
|
200
|
+
|
|
190
201
|
// Initialize list with evenly spaced positions
|
|
191
202
|
async function initializeList() {
|
|
192
203
|
await database.put({ list: "xyz", position: 1000 });
|
|
193
204
|
await database.put({ list: "xyz", position: 2000 });
|
|
194
205
|
await database.put({ list: "xyz", position: 3000 });
|
|
195
206
|
}
|
|
196
|
-
|
|
207
|
+
|
|
197
208
|
// Query items on list xyz, sorted by position. Note that useLiveQuery('list', { key:'xyz' }) would be the same docs, sorted chronologically by _id
|
|
198
|
-
const queryResult = useLiveQuery(
|
|
199
|
-
(doc) => [doc.list, doc.position],
|
|
200
|
-
{ prefix: ["xyz"] }
|
|
201
|
-
);
|
|
209
|
+
const queryResult = useLiveQuery((doc) => [doc.list, doc.position], { prefix: ["xyz"] });
|
|
202
210
|
|
|
203
211
|
// Insert between existing items using midpoint calculation
|
|
204
212
|
async function insertBetween(beforeDoc, afterDoc) {
|
|
205
213
|
const newPosition = (beforeDoc.position + afterDoc.position) / 2;
|
|
206
|
-
await database.put({
|
|
207
|
-
list: "xyz",
|
|
208
|
-
position: newPosition
|
|
214
|
+
await database.put({
|
|
215
|
+
list: "xyz",
|
|
216
|
+
position: newPosition,
|
|
209
217
|
});
|
|
210
218
|
}
|
|
211
219
|
|
|
@@ -213,7 +221,7 @@ function App() {
|
|
|
213
221
|
<div>
|
|
214
222
|
<h3>List xyz (Sorted)</h3>
|
|
215
223
|
<ul>
|
|
216
|
-
{queryResult.docs.map(doc => (
|
|
224
|
+
{queryResult.docs.map((doc) => (
|
|
217
225
|
<li key={doc._id}>
|
|
218
226
|
{doc._id}: position {doc.position}
|
|
219
227
|
</li>
|
|
@@ -268,10 +276,10 @@ database.subscribe((changes) => {
|
|
|
268
276
|
|
|
269
277
|
### Working with Files
|
|
270
278
|
|
|
271
|
-
Attach files to a document by adding them to the _files property. For example:
|
|
279
|
+
Attach files to a document by adding them to the \_files property. For example:
|
|
272
280
|
|
|
273
281
|
```html
|
|
274
|
-
<input accept="image/*" title="save to Fireproof" type="file" id="files" multiple
|
|
282
|
+
<input accept="image/*" title="save to Fireproof" type="file" id="files" multiple />
|
|
275
283
|
```
|
|
276
284
|
|
|
277
285
|
```js
|
|
@@ -279,11 +287,11 @@ function handleFiles() {
|
|
|
279
287
|
const fileList = this.files;
|
|
280
288
|
const doc = {
|
|
281
289
|
type: "files",
|
|
282
|
-
_files: {}
|
|
290
|
+
_files: {},
|
|
283
291
|
};
|
|
284
292
|
for (const file of fileList) {
|
|
285
293
|
// Assign each File object to the document
|
|
286
|
-
doc._files[file.name] = file;
|
|
294
|
+
doc._files[file.name] = file;
|
|
287
295
|
}
|
|
288
296
|
database.put(doc);
|
|
289
297
|
}
|
|
@@ -330,30 +338,33 @@ function handleSubmit(e) {
|
|
|
330
338
|
|
|
331
339
|
## Example React Application
|
|
332
340
|
|
|
333
|
-
Code listing for todo tracker App.jsx:
|
|
341
|
+
Code listing for todo tracker App.jsx. Note the code ordering: hooks, then handlers, then classNames right before JSX.
|
|
342
|
+
|
|
334
343
|
```js
|
|
335
344
|
import React from "react";
|
|
336
345
|
import { useFireproof } from "use-fireproof";
|
|
337
346
|
|
|
338
347
|
export default function App() {
|
|
348
|
+
// 1. Hooks and document shapes
|
|
339
349
|
const { useLiveQuery, useDocument, database } = useFireproof("todo-list-db");
|
|
340
350
|
|
|
341
351
|
const {
|
|
342
352
|
doc: newTodo,
|
|
343
353
|
merge: mergeNewTodo,
|
|
344
|
-
submit: submitNewTodo
|
|
354
|
+
submit: submitNewTodo,
|
|
345
355
|
} = useDocument({
|
|
346
356
|
todo: "",
|
|
347
357
|
type: "todo",
|
|
348
358
|
completed: false,
|
|
349
|
-
createdAt: Date.now()
|
|
359
|
+
createdAt: Date.now(),
|
|
350
360
|
});
|
|
351
361
|
|
|
352
|
-
const { docs: todos } = useLiveQuery("type", {
|
|
362
|
+
const { docs: todos } = useLiveQuery("type", {
|
|
353
363
|
key: "todo",
|
|
354
|
-
descending: true
|
|
364
|
+
descending: true,
|
|
355
365
|
});
|
|
356
366
|
|
|
367
|
+
// 2. Event handlers
|
|
357
368
|
const handleInputChange = (e) => {
|
|
358
369
|
mergeNewTodo({ todo: e.target.value });
|
|
359
370
|
};
|
|
@@ -363,13 +374,25 @@ export default function App() {
|
|
|
363
374
|
submitNewTodo();
|
|
364
375
|
};
|
|
365
376
|
|
|
377
|
+
// 3. ClassNames — right before JSX so colors stay consistent
|
|
378
|
+
const c = {
|
|
379
|
+
bg: "bg-white",
|
|
380
|
+
card: "bg-gray-50",
|
|
381
|
+
border: "border-gray-200",
|
|
382
|
+
accent: "bg-[#e63946]",
|
|
383
|
+
text: "text-gray-500",
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
// 4. JSX return
|
|
366
387
|
return (
|
|
367
|
-
<div className=
|
|
388
|
+
<div className={`max-w-md mx-auto p-4 ${c.bg} shadow rounded`}>
|
|
368
389
|
<h2 className="text-2xl font-bold mb-4">Todo List</h2>
|
|
369
390
|
<form onSubmit={handleSubmit} className="mb-4">
|
|
370
|
-
<label htmlFor="todo" className="block mb-2 font-semibold">
|
|
391
|
+
<label htmlFor="todo" className="block mb-2 font-semibold">
|
|
392
|
+
Todo
|
|
393
|
+
</label>
|
|
371
394
|
<input
|
|
372
|
-
className=
|
|
395
|
+
className={`w-full ${c.border} border rounded px-2 py-1`}
|
|
373
396
|
id="todo"
|
|
374
397
|
type="text"
|
|
375
398
|
onChange={handleInputChange}
|
|
@@ -378,7 +401,7 @@ export default function App() {
|
|
|
378
401
|
</form>
|
|
379
402
|
<ul className="space-y-3">
|
|
380
403
|
{todos.map((doc) => (
|
|
381
|
-
<li className=
|
|
404
|
+
<li className={`flex flex-col items-start p-2 ${c.border} border rounded ${c.card}`} key={doc._id}>
|
|
382
405
|
<div className="flex items-center justify-between w-full">
|
|
383
406
|
<div className="flex items-center">
|
|
384
407
|
<input
|
|
@@ -389,16 +412,11 @@ export default function App() {
|
|
|
389
412
|
/>
|
|
390
413
|
<span className="font-medium">{doc.todo}</span>
|
|
391
414
|
</div>
|
|
392
|
-
<button
|
|
393
|
-
className="text-sm bg-red-500 text-white px-2 py-1 rounded"
|
|
394
|
-
onClick={() => database.del(doc._id)}
|
|
395
|
-
>
|
|
415
|
+
<button className={`text-sm ${c.accent} text-white px-2 py-1 rounded`} onClick={() => database.del(doc._id)}>
|
|
396
416
|
Delete
|
|
397
417
|
</button>
|
|
398
418
|
</div>
|
|
399
|
-
<div className=
|
|
400
|
-
{new Date(doc.createdAt).toISOString()}
|
|
401
|
-
</div>
|
|
419
|
+
<div className={`text-xs ${c.text} mt-1`}>{new Date(doc.createdAt).toISOString()}</div>
|
|
402
420
|
</li>
|
|
403
421
|
))}
|
|
404
422
|
</ul>
|
|
@@ -409,37 +427,66 @@ export default function App() {
|
|
|
409
427
|
|
|
410
428
|
### Example Image Uploader
|
|
411
429
|
|
|
412
|
-
This React example shows a simple image uploader application that uses Fireproof to store and sort images by creation date. These APIs easily work with plain JavaScript also.
|
|
430
|
+
This React example shows a simple image uploader application that uses Fireproof to store and sort images by creation date. These APIs easily work with plain JavaScript also.
|
|
413
431
|
|
|
414
432
|
Code listing for App.jsx:
|
|
433
|
+
|
|
415
434
|
```js
|
|
416
435
|
import { useFireproof, ImgFile } from "use-fireproof";
|
|
417
|
-
import { useState
|
|
436
|
+
import { useState } from "react";
|
|
418
437
|
|
|
419
438
|
export default function App() {
|
|
439
|
+
// 1. Hooks and document shapes
|
|
420
440
|
const { useDocument, useLiveQuery } = useFireproof("image-uploads");
|
|
421
441
|
const { doc, merge, submit } = useDocument({ _files: {}, description: "" });
|
|
422
442
|
const { docs } = useLiveQuery("_id", { descending: true, limit: 5 });
|
|
423
443
|
const [error, setError] = useState(false);
|
|
424
444
|
|
|
445
|
+
// 2. Event handlers
|
|
446
|
+
const handleFileChange = (e) => {
|
|
447
|
+
if (e.target.files[0]) merge({ _files: { uploaded: e.target.files[0] } });
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
const handleUpload = () => {
|
|
451
|
+
if (doc.description.trim()) {
|
|
452
|
+
submit();
|
|
453
|
+
} else {
|
|
454
|
+
setError(true);
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
// 3. ClassNames
|
|
459
|
+
const c = {
|
|
460
|
+
bg: "bg-white",
|
|
461
|
+
card: "bg-gray-50",
|
|
462
|
+
accent: "bg-blue-500 hover:bg-blue-600",
|
|
463
|
+
text: "text-gray-700",
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
// 4. JSX return
|
|
425
467
|
return (
|
|
426
|
-
<div className=
|
|
468
|
+
<div className={`p-6 max-w-lg mx-auto ${c.bg} shadow-lg rounded-lg`}>
|
|
427
469
|
<h2 className="text-2xl font-bold mb-4">Image Uploader</h2>
|
|
428
|
-
<input type="file" accept="image/*" onChange={
|
|
429
|
-
<input
|
|
430
|
-
type="text"
|
|
431
|
-
placeholder="Enter description"
|
|
432
|
-
value={doc.description}
|
|
433
|
-
onChange={e => {
|
|
470
|
+
<input type="file" accept="image/*" onChange={handleFileChange} className="mb-2 border p-2 w-full rounded" />
|
|
471
|
+
<input
|
|
472
|
+
type="text"
|
|
473
|
+
placeholder="Enter description"
|
|
474
|
+
value={doc.description}
|
|
475
|
+
onChange={(e) => {
|
|
476
|
+
setError(false);
|
|
477
|
+
merge({ description: e.target.value });
|
|
478
|
+
}}
|
|
434
479
|
className={`w-full p-2 border rounded mb-4 ${error ? "border-red-500" : "border-gray-300"}`}
|
|
435
480
|
/>
|
|
436
|
-
<button onClick={
|
|
481
|
+
<button onClick={handleUpload} className={`px-4 py-2 ${c.accent} text-white rounded`}>
|
|
482
|
+
Upload
|
|
483
|
+
</button>
|
|
437
484
|
<h3 className="text-lg font-semibold mt-6">Recent Uploads</h3>
|
|
438
485
|
<div className="grid grid-cols-2 gap-4 mt-2">
|
|
439
|
-
{docs.map(doc => (
|
|
440
|
-
<div key={doc._id} className=
|
|
486
|
+
{docs.map((doc) => (
|
|
487
|
+
<div key={doc._id} className={`border p-2 rounded shadow-sm ${c.card}`}>
|
|
441
488
|
{doc._files?.uploaded && <ImgFile file={doc._files.uploaded} alt="Uploaded Image" className="w-full h-auto rounded" />}
|
|
442
|
-
<p className=
|
|
489
|
+
<p className={`text-sm ${c.text} mt-2`}>{doc.description || "No description"}</p>
|
|
443
490
|
</div>
|
|
444
491
|
))}
|
|
445
492
|
</div>
|
package/llms/image-gen.js
CHANGED
package/llms/image-gen.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-gen.js","sourceRoot":"","sources":["../../jsr/llms/image-gen.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,kBAAkB;IACzB,
|
|
1
|
+
{"version":3,"file":"image-gen.js","sourceRoot":"","sources":["../../jsr/llms/image-gen.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,kBAAkB;IACzB,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,0BAA0B;IACvC,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,QAAQ;CACrB,CAAC"}
|
|
@@ -7,7 +7,7 @@ The ImgGen component can be used in three ways:
|
|
|
7
7
|
1. **With no props** - Shows a form UI for users to enter a prompt and/or upload images:
|
|
8
8
|
|
|
9
9
|
```jsx
|
|
10
|
-
import { ImgGen } from
|
|
10
|
+
import { ImgGen } from "use-vibes";
|
|
11
11
|
|
|
12
12
|
function MyComponent() {
|
|
13
13
|
return <ImgGen />; // Shows built-in form for prompt entry and image upload
|
|
@@ -17,7 +17,7 @@ function MyComponent() {
|
|
|
17
17
|
2. **With a prompt prop** - Immediately generates an image (no form shown):
|
|
18
18
|
|
|
19
19
|
```jsx
|
|
20
|
-
import { ImgGen } from
|
|
20
|
+
import { ImgGen } from "use-vibes";
|
|
21
21
|
|
|
22
22
|
function MyComponent() {
|
|
23
23
|
return <ImgGen prompt="A sunset over mountains" />; // Direct generation, no form
|
|
@@ -27,32 +27,31 @@ function MyComponent() {
|
|
|
27
27
|
3. **With images prop** - Edits or combines images with AI (no form shown):
|
|
28
28
|
|
|
29
29
|
```jsx
|
|
30
|
-
import { ImgGen } from
|
|
30
|
+
import { ImgGen } from "use-vibes";
|
|
31
31
|
|
|
32
32
|
function MyComponent() {
|
|
33
33
|
const [files, setFiles] = useState([]);
|
|
34
34
|
return (
|
|
35
|
-
<ImgGen
|
|
36
|
-
prompt="Create a gift basket with these items"
|
|
35
|
+
<ImgGen
|
|
36
|
+
prompt="Create a gift basket with these items"
|
|
37
37
|
images={files} // Array of File objects
|
|
38
38
|
/>
|
|
39
39
|
);
|
|
40
40
|
}
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
4. **With an _id prop** - Loads a specific image from the database (no form shown):
|
|
43
|
+
4. **With an \_id prop** - Loads a specific image from the database (no form shown):
|
|
44
44
|
|
|
45
|
-
If there is no image generated for the document yet, but it has a `prompt` field, it will generate a new image with the prompt. If there an images is stored, at doc
|
|
45
|
+
If there is no image generated for the document yet, but it has a `prompt` field, it will generate a new image with the prompt. If there an images is stored, at doc.\_files.original, it will use that as the base image.
|
|
46
46
|
|
|
47
47
|
```jsx
|
|
48
|
-
import { ImgGen } from
|
|
48
|
+
import { ImgGen } from "use-vibes";
|
|
49
49
|
|
|
50
50
|
function MyComponent() {
|
|
51
51
|
return <ImgGen _id="my-image-id" />; // Loads specific image by ID
|
|
52
52
|
}
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
|
|
56
55
|
## List by ID
|
|
57
56
|
|
|
58
57
|
Images and prompts are tracked in a Fireproof database with a `type` of `image`. If a database is not provided, it uses `"ImgGen"` as the database name.
|
|
@@ -60,13 +59,13 @@ Images and prompts are tracked in a Fireproof database with a `type` of `image`.
|
|
|
60
59
|
Display stored images by their ID. Ensure you do this, so users can find the images they created.
|
|
61
60
|
|
|
62
61
|
```jsx
|
|
63
|
-
import { useFireproof } from
|
|
64
|
-
import { ImgGen } from
|
|
62
|
+
import { useFireproof } from "use-fireproof";
|
|
63
|
+
import { ImgGen } from "use-vibes";
|
|
65
64
|
|
|
66
65
|
function MyComponent() {
|
|
67
66
|
const { database, useLiveQuery } = useFireproof("my-db-name");
|
|
68
|
-
|
|
69
|
-
key:
|
|
67
|
+
const { docs: imageDocuments } = useLiveQuery("type", {
|
|
68
|
+
key: "image",
|
|
70
69
|
descending: true,
|
|
71
70
|
});
|
|
72
71
|
|
|
@@ -103,8 +102,8 @@ ImgGen supports custom styling through CSS variables or custom class names:
|
|
|
103
102
|
}
|
|
104
103
|
|
|
105
104
|
// With custom class names
|
|
106
|
-
<ImgGen
|
|
107
|
-
prompt="A landscape"
|
|
105
|
+
<ImgGen
|
|
106
|
+
prompt="A landscape"
|
|
108
107
|
className="my-custom-image"
|
|
109
108
|
classes={{
|
|
110
109
|
root: 'custom-container',
|