@vibes.diy/prompts 14.3.202 → 14.3.204
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/llms/access.md +4 -4
- package/llms/backend.md +1 -1
- package/llms/blockly.md +2 -2
- package/llms/bluesky.md +1 -1
- package/llms/board-games.md +95 -1
- package/llms/calendar.md +1 -1
- package/llms/callai.md +4 -4
- package/llms/connections.md +1 -1
- package/llms/create-vibe.md +3 -3
- package/llms/fireproof.md +7 -7
- package/llms/github.md +6 -2
- package/llms/image-gen.md +2 -2
- package/llms/index.d.ts +28 -28
- package/llms/index.js +84 -84
- package/llms/index.js.map +1 -1
- package/llms/maps.js +14 -2
- package/llms/maps.js.map +1 -1
- package/llms/maps.md +212 -9
- package/llms/match-style.md +1 -1
- package/llms/motion.md +7 -7
- package/llms/p5.md +1 -1
- package/llms/physics.md +2 -2
- package/llms/reskin.js +8 -1
- package/llms/reskin.js.map +1 -1
- package/llms/reskin.md +99 -20
- package/llms/richtext.md +5 -5
- package/llms/spotify.md +1 -1
- package/llms/stripe-subscriptions.md +1 -1
- package/llms/stripe.md +3 -3
- package/llms/strudel.md +3 -3
- package/llms/three-js.md +4 -4
- package/llms/touch-games.js +1 -1
- package/llms/touch-games.js.map +1 -1
- package/llms/touch-games.md +3 -3
- package/llms/ui-blog.d.ts +2 -0
- package/llms/ui-blog.js +7 -0
- package/llms/ui-blog.js.map +1 -0
- package/llms/{pouf-blog.md → ui-blog.md} +10 -10
- package/llms/ui-booking.d.ts +2 -0
- package/llms/ui-booking.js +7 -0
- package/llms/ui-booking.js.map +1 -0
- package/llms/{pouf-booking.md → ui-booking.md} +8 -8
- package/llms/ui-calendar.d.ts +2 -0
- package/llms/ui-calendar.js +7 -0
- package/llms/ui-calendar.js.map +1 -0
- package/llms/{pouf-calendar.md → ui-calendar.md} +5 -5
- package/llms/ui-chat.d.ts +2 -0
- package/llms/ui-chat.js +7 -0
- package/llms/ui-chat.js.map +1 -0
- package/llms/{pouf-chat.md → ui-chat.md} +4 -4
- package/llms/ui-contact.d.ts +2 -0
- package/llms/ui-contact.js +7 -0
- package/llms/ui-contact.js.map +1 -0
- package/llms/{pouf-contact.md → ui-contact.md} +7 -7
- package/llms/ui-course.d.ts +2 -0
- package/llms/ui-course.js +7 -0
- package/llms/ui-course.js.map +1 -0
- package/llms/{pouf-course.md → ui-course.md} +9 -9
- package/llms/ui-crm.d.ts +2 -0
- package/llms/ui-crm.js +7 -0
- package/llms/ui-crm.js.map +1 -0
- package/llms/{pouf-crm.md → ui-crm.md} +5 -5
- package/llms/ui-dashboard.d.ts +2 -0
- package/llms/ui-dashboard.js +7 -0
- package/llms/ui-dashboard.js.map +1 -0
- package/llms/{pouf-dashboard.md → ui-dashboard.md} +7 -7
- package/llms/ui-editorial.d.ts +2 -0
- package/llms/ui-editorial.js +7 -0
- package/llms/ui-editorial.js.map +1 -0
- package/llms/{pouf-editorial.md → ui-editorial.md} +5 -5
- package/llms/ui-event.d.ts +2 -0
- package/llms/ui-event.js +7 -0
- package/llms/ui-event.js.map +1 -0
- package/llms/{pouf-event.md → ui-event.md} +5 -5
- package/llms/ui-feed.d.ts +2 -0
- package/llms/ui-feed.js +7 -0
- package/llms/ui-feed.js.map +1 -0
- package/llms/{pouf-feed.md → ui-feed.md} +5 -5
- package/llms/ui-game.d.ts +2 -0
- package/llms/ui-game.js +7 -0
- package/llms/ui-game.js.map +1 -0
- package/llms/{pouf-game.md → ui-game.md} +6 -6
- package/llms/ui-inbox.d.ts +2 -0
- package/llms/ui-inbox.js +7 -0
- package/llms/ui-inbox.js.map +1 -0
- package/llms/{pouf-inbox.md → ui-inbox.md} +5 -5
- package/llms/ui-inventory.d.ts +2 -0
- package/llms/ui-inventory.js +7 -0
- package/llms/ui-inventory.js.map +1 -0
- package/llms/{pouf-inventory.md → ui-inventory.md} +5 -5
- package/llms/ui-kanban.d.ts +2 -0
- package/llms/ui-kanban.js +7 -0
- package/llms/ui-kanban.js.map +1 -0
- package/llms/{pouf-kanban.md → ui-kanban.md} +5 -5
- package/llms/ui-landing.d.ts +2 -0
- package/llms/ui-landing.js +7 -0
- package/llms/ui-landing.js.map +1 -0
- package/llms/{pouf-landing.md → ui-landing.md} +6 -6
- package/llms/ui-login.d.ts +2 -0
- package/llms/ui-login.js +7 -0
- package/llms/ui-login.js.map +1 -0
- package/llms/{pouf-login.md → ui-login.md} +7 -7
- package/llms/ui-music.d.ts +2 -0
- package/llms/ui-music.js +7 -0
- package/llms/ui-music.js.map +1 -0
- package/llms/{pouf-music.md → ui-music.md} +6 -6
- package/llms/ui-onboarding.d.ts +2 -0
- package/llms/ui-onboarding.js +7 -0
- package/llms/ui-onboarding.js.map +1 -0
- package/llms/{pouf-onboarding.md → ui-onboarding.md} +5 -5
- package/llms/ui-pricing.d.ts +2 -0
- package/llms/ui-pricing.js +7 -0
- package/llms/ui-pricing.js.map +1 -0
- package/llms/{pouf-pricing.md → ui-pricing.md} +5 -5
- package/llms/ui-profile.d.ts +2 -0
- package/llms/ui-profile.js +7 -0
- package/llms/ui-profile.js.map +1 -0
- package/llms/{pouf-profile.md → ui-profile.md} +4 -4
- package/llms/ui-quiz.d.ts +2 -0
- package/llms/ui-quiz.js +7 -0
- package/llms/ui-quiz.js.map +1 -0
- package/llms/{pouf-quiz.md → ui-quiz.md} +6 -6
- package/llms/ui-settings.d.ts +2 -0
- package/llms/ui-settings.js +7 -0
- package/llms/ui-settings.js.map +1 -0
- package/llms/{pouf-settings.md → ui-settings.md} +5 -5
- package/llms/ui-storefront.d.ts +2 -0
- package/llms/ui-storefront.js +7 -0
- package/llms/ui-storefront.js.map +1 -0
- package/llms/{pouf-storefront.md → ui-storefront.md} +9 -9
- package/llms/ui-support.d.ts +2 -0
- package/llms/ui-support.js +7 -0
- package/llms/ui-support.js.map +1 -0
- package/llms/{pouf-support.md → ui-support.md} +5 -5
- package/llms/ui-testimonials.d.ts +2 -0
- package/llms/ui-testimonials.js +7 -0
- package/llms/ui-testimonials.js.map +1 -0
- package/llms/{pouf-testimonials.md → ui-testimonials.md} +6 -6
- package/llms/ui-todo.d.ts +2 -0
- package/llms/ui-todo.js +7 -0
- package/llms/ui-todo.js.map +1 -0
- package/llms/{pouf-todo.md → ui-todo.md} +5 -5
- package/llms/ui-weather.d.ts +2 -0
- package/llms/ui-weather.js +7 -0
- package/llms/ui-weather.js.map +1 -0
- package/llms/{pouf-weather.md → ui-weather.md} +5 -5
- package/llms/use-vibe.md +4 -4
- package/llms/use-viewer.md +5 -5
- package/llms/voxel.md +1 -1
- package/llms/web-audio.md +49 -26
- package/llms/worlds.md +3 -3
- package/llms/youtube.md +1 -1
- package/package.json +5 -5
- package/system-prompt-initial-instant.md +3 -3
- package/system-prompt.md +3 -3
- package/themes/colorsets.js +7 -7
- package/themes/colorsets.js.map +1 -1
- package/themes/looks/pouf/brief.md +87 -85
- package/themes/looks/pouf/catalog.generated.d.ts +1 -1
- package/themes/looks/pouf/catalog.generated.js +47 -17
- package/themes/looks/pouf/catalog.generated.js.map +1 -1
- package/themes/looks/pouf/variety.js +4 -4
- package/themes/looks/pouf/variety.js.map +1 -1
- package/llms/pouf-blog.d.ts +0 -2
- package/llms/pouf-blog.js +0 -6
- package/llms/pouf-blog.js.map +0 -1
- package/llms/pouf-booking.d.ts +0 -2
- package/llms/pouf-booking.js +0 -6
- package/llms/pouf-booking.js.map +0 -1
- package/llms/pouf-calendar.d.ts +0 -2
- package/llms/pouf-calendar.js +0 -6
- package/llms/pouf-calendar.js.map +0 -1
- package/llms/pouf-chat.d.ts +0 -2
- package/llms/pouf-chat.js +0 -6
- package/llms/pouf-chat.js.map +0 -1
- package/llms/pouf-contact.d.ts +0 -2
- package/llms/pouf-contact.js +0 -6
- package/llms/pouf-contact.js.map +0 -1
- package/llms/pouf-course.d.ts +0 -2
- package/llms/pouf-course.js +0 -6
- package/llms/pouf-course.js.map +0 -1
- package/llms/pouf-crm.d.ts +0 -2
- package/llms/pouf-crm.js +0 -6
- package/llms/pouf-crm.js.map +0 -1
- package/llms/pouf-dashboard.d.ts +0 -2
- package/llms/pouf-dashboard.js +0 -6
- package/llms/pouf-dashboard.js.map +0 -1
- package/llms/pouf-editorial.d.ts +0 -2
- package/llms/pouf-editorial.js +0 -6
- package/llms/pouf-editorial.js.map +0 -1
- package/llms/pouf-event.d.ts +0 -2
- package/llms/pouf-event.js +0 -6
- package/llms/pouf-event.js.map +0 -1
- package/llms/pouf-feed.d.ts +0 -2
- package/llms/pouf-feed.js +0 -6
- package/llms/pouf-feed.js.map +0 -1
- package/llms/pouf-game.d.ts +0 -2
- package/llms/pouf-game.js +0 -6
- package/llms/pouf-game.js.map +0 -1
- package/llms/pouf-inbox.d.ts +0 -2
- package/llms/pouf-inbox.js +0 -6
- package/llms/pouf-inbox.js.map +0 -1
- package/llms/pouf-inventory.d.ts +0 -2
- package/llms/pouf-inventory.js +0 -6
- package/llms/pouf-inventory.js.map +0 -1
- package/llms/pouf-kanban.d.ts +0 -2
- package/llms/pouf-kanban.js +0 -6
- package/llms/pouf-kanban.js.map +0 -1
- package/llms/pouf-landing.d.ts +0 -2
- package/llms/pouf-landing.js +0 -6
- package/llms/pouf-landing.js.map +0 -1
- package/llms/pouf-login.d.ts +0 -2
- package/llms/pouf-login.js +0 -6
- package/llms/pouf-login.js.map +0 -1
- package/llms/pouf-music.d.ts +0 -2
- package/llms/pouf-music.js +0 -6
- package/llms/pouf-music.js.map +0 -1
- package/llms/pouf-onboarding.d.ts +0 -2
- package/llms/pouf-onboarding.js +0 -6
- package/llms/pouf-onboarding.js.map +0 -1
- package/llms/pouf-pricing.d.ts +0 -2
- package/llms/pouf-pricing.js +0 -6
- package/llms/pouf-pricing.js.map +0 -1
- package/llms/pouf-profile.d.ts +0 -2
- package/llms/pouf-profile.js +0 -6
- package/llms/pouf-profile.js.map +0 -1
- package/llms/pouf-quiz.d.ts +0 -2
- package/llms/pouf-quiz.js +0 -6
- package/llms/pouf-quiz.js.map +0 -1
- package/llms/pouf-settings.d.ts +0 -2
- package/llms/pouf-settings.js +0 -6
- package/llms/pouf-settings.js.map +0 -1
- package/llms/pouf-storefront.d.ts +0 -2
- package/llms/pouf-storefront.js +0 -6
- package/llms/pouf-storefront.js.map +0 -1
- package/llms/pouf-support.d.ts +0 -2
- package/llms/pouf-support.js +0 -6
- package/llms/pouf-support.js.map +0 -1
- package/llms/pouf-testimonials.d.ts +0 -2
- package/llms/pouf-testimonials.js +0 -6
- package/llms/pouf-testimonials.js.map +0 -1
- package/llms/pouf-todo.d.ts +0 -2
- package/llms/pouf-todo.js +0 -6
- package/llms/pouf-todo.js.map +0 -1
- package/llms/pouf-weather.d.ts +0 -2
- package/llms/pouf-weather.js +0 -6
- package/llms/pouf-weather.js.map +0 -1
package/llms/richtext.md
CHANGED
|
@@ -10,8 +10,8 @@ in Fireproof, saves after typing pauses, loads a document without echoing it
|
|
|
10
10
|
back as a save, and styles the written text with Tailwind on the host.
|
|
11
11
|
|
|
12
12
|
The sibling boundary: a short field (a title, a comment, a caption) is
|
|
13
|
-
|
|
14
|
-
of stories with stages is `
|
|
13
|
+
the UI's `Textarea` in a `Field`; a feed of posts is `ui-feed`; a pipeline
|
|
14
|
+
of stories with stages is `ui-editorial`. Rich text is the right call when
|
|
15
15
|
the person is writing a page.
|
|
16
16
|
|
|
17
17
|
The worked examples below were built and measured for this doc (Chromium,
|
|
@@ -165,7 +165,7 @@ export function createEditor(host, { content = EMPTY_DOC, placeholder = "Start w
|
|
|
165
165
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
166
166
|
import { useFireproof } from "use-fireproof";
|
|
167
167
|
import { useVibe, useViewer } from "use-vibes";
|
|
168
|
-
import { Badge, Button, Card, Heading, IconButton, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/
|
|
168
|
+
import { Badge, Button, Card, Heading, IconButton, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
|
|
169
169
|
import { EMPTY_DOC, createEditor, titleOf } from "./lib/editor.js";
|
|
170
170
|
|
|
171
171
|
// The written page is styled from the host: Tailwind reaches into the editor with arbitrary
|
|
@@ -471,7 +471,7 @@ through Tailwind's arbitrary variants**: `[&_h1]:text-2xl`,
|
|
|
471
471
|
`[&_.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]`.
|
|
472
472
|
The JSX stays class-only and the theme tokens (`text-primary`,
|
|
473
473
|
`text-muted-foreground`, `bg-muted`) carry the owner's restyle into the
|
|
474
|
-
written page. Measured: the
|
|
474
|
+
written page. Measured: the design lint passes a host carrying these classes.
|
|
475
475
|
|
|
476
476
|
## Commands and the toolbar
|
|
477
477
|
|
|
@@ -553,7 +553,7 @@ export function createEditor(host, { content = EMPTY_DOC, placeholder = "Start w
|
|
|
553
553
|
import React, { useEffect, useRef, useState } from "react";
|
|
554
554
|
import { useFireproof } from "use-fireproof";
|
|
555
555
|
import { useVibe, useViewer } from "use-vibes";
|
|
556
|
-
import { Badge, Button, Card, Heading, Row, Spacer, Stack, Text } from "@vibes.diy/
|
|
556
|
+
import { Badge, Button, Card, Heading, Row, Spacer, Stack, Text } from "@vibes.diy/ui";
|
|
557
557
|
import { EMPTY_DOC, createEditor } from "./lib/editor.js";
|
|
558
558
|
|
|
559
559
|
const PAGE_ID = "page:home";
|
package/llms/spotify.md
CHANGED
|
@@ -325,7 +325,7 @@ function artistRow(a) {
|
|
|
325
325
|
```jsx app=spotify-browser
|
|
326
326
|
import React, { useEffect, useRef, useState } from "react";
|
|
327
327
|
import { apiFetch } from "use-vibes";
|
|
328
|
-
import { Badge, Button, Field, Heading, Input, Row, Stack, Text } from "@vibes.diy/
|
|
328
|
+
import { Badge, Button, Field, Heading, Input, Row, Stack, Text } from "@vibes.diy/ui";
|
|
329
329
|
|
|
330
330
|
// The setup verdict, read on mount and again whenever the app comes back into view: the owner
|
|
331
331
|
// sets the pair in another tab and returns, and search unlocks without a reload.
|
|
@@ -683,7 +683,7 @@ export function club(doc, oldDoc, user, ctx) {
|
|
|
683
683
|
import React, { useEffect, useRef, useState } from "react";
|
|
684
684
|
import { useFireproof } from "use-fireproof";
|
|
685
685
|
import { apiFetch, useViewer } from "use-vibes";
|
|
686
|
-
import { Badge, Button, Heading, Row, Stack, Text } from "@vibes.diy/
|
|
686
|
+
import { Badge, Button, Heading, Row, Stack, Text } from "@vibes.diy/ui";
|
|
687
687
|
|
|
688
688
|
// The setup verdict, read on mount and again whenever the app comes back into view: the owner
|
|
689
689
|
// connects Stripe or saves the portal in another tab and returns, and the Join buttons unlock
|
package/llms/stripe.md
CHANGED
|
@@ -570,7 +570,7 @@ export function orders(doc, oldDoc, user, ctx) {
|
|
|
570
570
|
import React, { useEffect, useRef, useState } from "react";
|
|
571
571
|
import { useFireproof } from "use-fireproof";
|
|
572
572
|
import { apiFetch, useVibe } from "use-vibes";
|
|
573
|
-
import { Badge, Button, Heading, Row, Stack, Text } from "@vibes.diy/
|
|
573
|
+
import { Badge, Button, Heading, Row, Stack, Text } from "@vibes.diy/ui";
|
|
574
574
|
|
|
575
575
|
// The setup verdict, read on mount and again whenever the app comes back into view: the owner
|
|
576
576
|
// connects Stripe in another tab and returns, and the Pay buttons unlock without a reload.
|
|
@@ -1184,8 +1184,8 @@ export function checks(doc, oldDoc, user, ctx) {
|
|
|
1184
1184
|
import React, { useEffect, useRef, useState } from "react";
|
|
1185
1185
|
import { useFireproof } from "use-fireproof";
|
|
1186
1186
|
import { apiFetch } from "use-vibes";
|
|
1187
|
-
import { Badge, Button, Field, Figure, Heading, Input, Metric, Row, Segmented, Stack, Text } from "@vibes.diy/
|
|
1188
|
-
import { Checkbox } from "@vibes.diy/
|
|
1187
|
+
import { Badge, Button, Field, Figure, Heading, Input, Metric, Row, Segmented, Stack, Text } from "@vibes.diy/ui";
|
|
1188
|
+
import { Checkbox } from "@vibes.diy/ui/interactive";
|
|
1189
1189
|
|
|
1190
1190
|
const money = (cents) => `$${(cents / 100).toFixed(2)}`;
|
|
1191
1191
|
const post = (body) => ({ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
|
package/llms/strudel.md
CHANGED
|
@@ -207,7 +207,7 @@ with every write gated on `can`.
|
|
|
207
207
|
import React, { useEffect, useMemo, useState } from "react";
|
|
208
208
|
import { useFireproof } from "use-fireproof";
|
|
209
209
|
import { callAI, useVibe, useViewer } from "use-vibes";
|
|
210
|
-
import { Badge, Button, Card, Field, Heading, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/
|
|
210
|
+
import { Badge, Button, Card, Field, Heading, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
|
|
211
211
|
import { EXAMPLES, onPatternError, play, stop } from "./lib/strudel.js";
|
|
212
212
|
import { rewritePrompt } from "./lib/pattern-prompt.js";
|
|
213
213
|
|
|
@@ -446,8 +446,8 @@ A groovebox whose lights follow the music, built on the same module:
|
|
|
446
446
|
import React, { useEffect, useRef, useState } from "react";
|
|
447
447
|
import { useFireproof } from "use-fireproof";
|
|
448
448
|
import { useVibe, useViewer } from "use-vibes";
|
|
449
|
-
import { Badge, Button, Card, Field, Heading, Icon, IconButton, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/
|
|
450
|
-
import { Slider } from "@vibes.diy/
|
|
449
|
+
import { Badge, Button, Card, Field, Heading, Icon, IconButton, Input, Row, Skeleton, Spacer, Stack, Text } from "@vibes.diy/ui";
|
|
450
|
+
import { Slider } from "@vibes.diy/ui/interactive";
|
|
451
451
|
import { gridToCode, play, stop } from "./lib/strudel.js";
|
|
452
452
|
|
|
453
453
|
const ROWS = ["bd", "sd", "hh", "cp"];
|
package/llms/three-js.md
CHANGED
|
@@ -1258,7 +1258,7 @@ import React, { useState, useEffect, useRef, useCallback } from "react";
|
|
|
1258
1258
|
import { useFireproof } from "use-fireproof";
|
|
1259
1259
|
import * as THREE from "three";
|
|
1260
1260
|
import { useWorldControls } from "use-vibes";
|
|
1261
|
-
import { Card, Heading, IconButton, Stack, Text } from "@vibes.diy/
|
|
1261
|
+
import { Card, Heading, IconButton, Stack, Text } from "@vibes.diy/ui";
|
|
1262
1262
|
|
|
1263
1263
|
export default function SkyGlider() {
|
|
1264
1264
|
const { database, useLiveQuery } = useFireproof("skyGliderScores");
|
|
@@ -1705,8 +1705,8 @@ import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
|
|
1705
1705
|
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
|
|
1706
1706
|
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
|
|
1707
1707
|
import { HalftonePass } from "three/addons/postprocessing/HalftonePass.js";
|
|
1708
|
-
import { Button, Card, Field, Heading, Input, RowCard, Stack, Text } from "@vibes.diy/
|
|
1709
|
-
import { Checkbox, Select, Separator, Slider } from "@vibes.diy/
|
|
1708
|
+
import { Button, Card, Field, Heading, Input, RowCard, Stack, Text } from "@vibes.diy/ui";
|
|
1709
|
+
import { Checkbox, Select, Separator, Slider } from "@vibes.diy/ui/interactive";
|
|
1710
1710
|
|
|
1711
1711
|
export default function HalftoneArtStudio() {
|
|
1712
1712
|
const { database, useLiveQuery } = useFireproof("halftoneStudio");
|
|
@@ -2061,7 +2061,7 @@ export default function HalftoneArtStudio() {
|
|
|
2061
2061
|
<div className="relative h-dvh w-full overflow-hidden bg-background text-foreground font-sans">
|
|
2062
2062
|
<canvas ref={canvasRef} className="absolute inset-0 select-none touch-none" />
|
|
2063
2063
|
|
|
2064
|
-
{/* One control panel. The
|
|
2064
|
+
{/* One control panel. The UI's `Card` IS the panel — it takes no className,
|
|
2065
2065
|
so a plain wrapper carries its placement; the cushion, corner and ink are its own. */}
|
|
2066
2066
|
<div className="absolute inset-y-4 left-4 w-80 overflow-y-auto">
|
|
2067
2067
|
<Card>
|
package/llms/touch-games.js
CHANGED
|
@@ -2,7 +2,7 @@ export const touchGamesConfig = {
|
|
|
2
2
|
name: "touch-games",
|
|
3
3
|
label: "Touch games",
|
|
4
4
|
description: "Phone-first controls for anything played or steered in real time — load it beside three-js, voxel, " +
|
|
5
|
-
"physics, p5, worlds or
|
|
5
|
+
"physics, p5, worlds or ui-game for every game, 3D scene you move through, or canvas toy: the play area " +
|
|
6
6
|
"is the controller (select-none touch-none surface, Pointer Events with pointer capture), swipes that fire " +
|
|
7
7
|
"mid-move with chaining, tap vs swipe on one surface, a floating ghost stick under the thumb, hold-to-boost " +
|
|
8
8
|
"with drag steering, pull-back-and-release aiming, gesture trails and feedback, keyboard twins for desktop, " +
|
package/llms/touch-games.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"touch-games.js","sourceRoot":"","sources":["../../jsr/llms/touch-games.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAc;IACzC,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,aAAa;IACpB,WAAW,EACT,qGAAqG;QACrG,
|
|
1
|
+
{"version":3,"file":"touch-games.js","sourceRoot":"","sources":["../../jsr/llms/touch-games.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAc;IACzC,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,aAAa;IACpB,WAAW,EACT,qGAAqG;QACrG,yGAAyG;QACzG,4GAA4G;QAC5G,6GAA6G;QAC7G,6GAA6G;QAC7G,iHAAiH;QACjH,2DAA2D;QAC3D,uGAAuG;QACvG,mEAAmE;IAKrE,IAAI,EAAE;QACJ,OAAO;QACP,gBAAgB;QAChB,aAAa;QACb,YAAY;QACZ,YAAY;QACZ,aAAa;QACb,cAAc;QACd,aAAa;QACb,UAAU;QACV,QAAQ;QACR,OAAO;QACP,QAAQ;QACR,OAAO;QACP,SAAS;QACT,YAAY;QACZ,gBAAgB;QAChB,SAAS;QACT,aAAa;QACb,aAAa;QACb,OAAO;QACP,SAAS;QACT,WAAW;QACX,SAAS;QACT,WAAW;QACX,UAAU;QACV,QAAQ;QACR,YAAY;QACZ,cAAc;QACd,cAAc;QACd,aAAa;QACb,SAAS;KACV;CACF,CAAC"}
|
package/llms/touch-games.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Touch games — the play area is the controller
|
|
2
2
|
|
|
3
3
|
Load this beside whatever draws the game — `three-js`, `voxel`, `physics`, `p5`, `worlds`,
|
|
4
|
-
`
|
|
4
|
+
`ui-game`, a plain `<canvas>` — whenever the app is something you play or steer in real time:
|
|
5
5
|
a runner, a racer, a flyer, a shooter, a snake, a launcher, a platformer, a pinball table, a
|
|
6
6
|
marble maze, a 3D scene you move through, a toy you drag around. Most people open a vibe on a
|
|
7
7
|
phone, one-handed. The game that feels great there is the one where the thumb rests **on the
|
|
@@ -208,7 +208,7 @@ orbits, a click is `onTap`, a right-click is `onHold`, and the wheel zooms.
|
|
|
208
208
|
import React from "react";
|
|
209
209
|
import * as THREE from "three";
|
|
210
210
|
import { useWorldControls } from "use-vibes";
|
|
211
|
-
import { Button, Card, Heading, IconButton, Stack, Text } from "@vibes.diy/
|
|
211
|
+
import { Button, Card, Heading, IconButton, Stack, Text } from "@vibes.diy/ui";
|
|
212
212
|
|
|
213
213
|
const VIEWS = ["Free cam", "First person", "Shoulder view"];
|
|
214
214
|
const HINT = {
|
|
@@ -407,7 +407,7 @@ snake by changing what `move()` does.
|
|
|
407
407
|
### `App.jsx`
|
|
408
408
|
```jsx
|
|
409
409
|
import React from "react";
|
|
410
|
-
import { Card, Heading, IconButton, Stack, Text } from "@vibes.diy/
|
|
410
|
+
import { Card, Heading, IconButton, Stack, Text } from "@vibes.diy/ui";
|
|
411
411
|
|
|
412
412
|
const TUNE = {
|
|
413
413
|
swipePx: 26, // travel from the anchor before a swipe fires (raise to 30–34 if a resting thumb misfires)
|
package/llms/ui-blog.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-blog.js","sourceRoot":"","sources":["../../jsr/llms/ui-blog.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,CAAC,WAAW,CAAC;IACtB,KAAK,EAAE,YAAY;IACnB,WAAW,EAAE,gEAAgE;CAC9E,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Blog
|
|
2
2
|
|
|
3
3
|
A blog with a front page and a reading view: a bakery's recipe notes, a travel journal, a club's match reports, a studio's news. Reach for it whenever the app's core is posts written by a few people and read by many, newest first, sorted into a handful of categories. Each post is its own document, so the blog is there on the next visit and on every device, and a new post appears for every reader as soon as it is published.
|
|
4
4
|
|
|
5
|
-
Built from @vibes.diy/
|
|
5
|
+
Built from @vibes.diy/ui components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
|
7
7
|
## The block
|
|
8
8
|
|
|
9
|
-
Two views, one job each. The front page opens with an `Eyebrow`, the `Heading` and a muted post count beside a `Write a post` button, the front page's one lead, which opens a `Dialog` with the writing form (title, category, body, each in its own `Field` with its own error). The newest post leads on a `Card` laid out with `Grid cols="sidebar"` beside a decorative `orange` `
|
|
9
|
+
Two views, one job each. The front page opens with an `Eyebrow`, the `Heading` and a muted post count beside a `Write a post` button, the front page's one lead, which opens a `Dialog` with the writing form (title, category, body, each in its own `Field` with its own error). The newest post leads on a `Card` laid out with `Grid cols="sidebar"` beside a decorative `orange` `IconTile`; under it a `Segmented` category filter (`tone="info"`) narrows a two-column `Grid` of post `Card`s, each with an `info` category `Badge`, the title, an excerpt in muted `Text`, the writer as a `ViewerTag` with a muted date, and a quiet `Read` button; `Pagination` pages through them and an `Empty` stands in when a category has nothing. Opening a post swaps in the reading view: a quiet `IconButton` back, the title as the `Heading`, the byline and the body as `Text` paragraphs, with a quiet `Delete post` (toned `down`) behind a `Confirm` wearing `tone="down"`, both showing `loading` while the delete lands. Every write waits on its `can` verdict from `useVibe("blog")`, the database the posts live in: the write button gives way to a `Skeleton` inside an `aria-busy` wrapper while the verdict resolves, to a quiet `Sign in to write` wired to `useViewer().requestLogin()` for a visitor who has not signed in, and to a sentence in the app's own words when writing is closed; `Delete post` renders only where `can.delete(post).ok`.
|
|
10
10
|
|
|
11
11
|
### `App.jsx`
|
|
12
12
|
```jsx
|
|
@@ -15,7 +15,7 @@ import { useFireproof } from "use-fireproof";
|
|
|
15
15
|
import { useViewer, useVibe } from "use-vibes";
|
|
16
16
|
import {
|
|
17
17
|
Badge,
|
|
18
|
-
|
|
18
|
+
IconTile,
|
|
19
19
|
Button,
|
|
20
20
|
Card,
|
|
21
21
|
Empty,
|
|
@@ -33,8 +33,8 @@ import {
|
|
|
33
33
|
Stack,
|
|
34
34
|
Text,
|
|
35
35
|
Textarea,
|
|
36
|
-
} from "@vibes.diy/
|
|
37
|
-
import { Confirm, Dialog, Select, Toaster, toast } from "@vibes.diy/
|
|
36
|
+
} from "@vibes.diy/ui";
|
|
37
|
+
import { Confirm, Dialog, Select, Toaster, toast } from "@vibes.diy/ui/interactive";
|
|
38
38
|
|
|
39
39
|
const CATEGORIES = [
|
|
40
40
|
{ value: "recipes", label: "Recipes" },
|
|
@@ -164,7 +164,7 @@ export default function App() {
|
|
|
164
164
|
</Row>
|
|
165
165
|
)}
|
|
166
166
|
</Stack>
|
|
167
|
-
<div className="
|
|
167
|
+
<div className="ui-toasts">
|
|
168
168
|
<Toaster />
|
|
169
169
|
</div>
|
|
170
170
|
</main>
|
|
@@ -246,7 +246,7 @@ export default function App() {
|
|
|
246
246
|
</Button>
|
|
247
247
|
</Row>
|
|
248
248
|
</Stack>
|
|
249
|
-
<
|
|
249
|
+
<IconTile icon="sparkle" tone="orange" size="lg" />
|
|
250
250
|
</Grid>
|
|
251
251
|
</Card>
|
|
252
252
|
|
|
@@ -286,7 +286,7 @@ export default function App() {
|
|
|
286
286
|
</>
|
|
287
287
|
)}
|
|
288
288
|
</Stack>
|
|
289
|
-
<div className="
|
|
289
|
+
<div className="ui-toasts">
|
|
290
290
|
<Toaster />
|
|
291
291
|
</div>
|
|
292
292
|
</main>
|
|
@@ -298,7 +298,7 @@ export default function App() {
|
|
|
298
298
|
|
|
299
299
|
- Swap `CATEGORIES` for the blog's own sections; the filter and the form's `Select` both read from it, so a new section appears in both. Keep the category `Badge`s on one neutral tone (`info`): a category is a label, not a verdict.
|
|
300
300
|
- Keep one document per post with its `authorHandle`; the byline is always a `ViewerTag`, never a typed name.
|
|
301
|
-
- A cover photo is a `_files` attachment on the post, shown with `Figure` in place of the featured `
|
|
301
|
+
- A cover photo is a `_files` attachment on the post, shown with `Figure` in place of the featured `IconTile`; drafts that aren't ready yet are a `status` field filtered out of the front page (the editorial block walks posts through that pipeline).
|
|
302
302
|
- Editing a post is the same form, prefilled, writing behind `can.edit(post)`; keep `Delete post` quiet and behind its `Confirm`.
|
|
303
303
|
- A new write surface gets its own verdict: `can.create(draft)` with the fields the write stamps, `can.edit(doc)` or `can.delete(doc)` on the document it changes, always on `useVibe` of the database it writes.
|
|
304
304
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-booking.js","sourceRoot":"","sources":["../../jsr/llms/ui-booking.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,CAAC,cAAc,CAAC;IACzB,KAAK,EAAE,eAAe;IACtB,WAAW,EAAE,iEAAiE;CAC/E,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Booking
|
|
2
2
|
|
|
3
3
|
An appointment booker: pick a service, a day and a free time, add a name, review, confirm. It fits a massage practice's sessions, a tutor's lessons, a studio's portrait slots or a repair café's drop-in times. Reach for it whenever the app's core is people claiming time slots that only one person can hold. Every booking persists as its own document and availability is worked out from them, so a taken time disappears for everyone and the booker finds their sessions on every visit.
|
|
4
4
|
|
|
5
|
-
Built from @vibes.diy/
|
|
5
|
+
Built from @vibes.diy/ui components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
|
7
7
|
## The block
|
|
8
8
|
|
|
9
|
-
Two cards beside each other in a `Grid cols="sidebar"`. The main side opens with an `Eyebrow`, the `Heading` and a muted promise, then the person's own bookings on a `Card`. Each booking shows a `Badge`: `up` when confirmed, `warn` when someone else got the time first. Each one has a quiet `Cancel` behind a `Confirm` wearing `tone="down"`, offered only where `can.delete(booking).ok`. The side holds the wizard, one step at a time under an `Eyebrow` and a `Progress` bar (`tone="info"`): each service is a clickable `RowCard` with a decorative `orange` `
|
|
9
|
+
Two cards beside each other in a `Grid cols="sidebar"`. The main side opens with an `Eyebrow`, the `Heading` and a muted promise, then the person's own bookings on a `Card`. Each booking shows a `Badge`: `up` when confirmed, `warn` when someone else got the time first. Each one has a quiet `Cancel` behind a `Confirm` wearing `tone="down"`, offered only where `can.delete(booking).ok`. The side holds the wizard, one step at a time under an `Eyebrow` and a `Progress` bar (`tone="info"`): each service is a clickable `RowCard` with a decorative `orange` `IconTile`; the day is a `Segmented` (`tone="info"`) and the time a `RadioGroup` of only the free times, with a muted line when a day is full; the details are a name `Input` in a `Field` with its own error (nothing private, because every booking is readable so free times can be worked out); and the review ends in `Confirm booking`, that step's one lead, which shows `loading` while the write lands. Each booking is its own document, never a flag on a shared calendar document. Two people can confirm the same time at once, and sync keeps both documents, so availability is derived: a slot belongs to its earliest booking (by `createdAt`, then `_id`). A later one is shown to its booker as a clash, with a `Pick another time` button that removes it and keeps their details. Confirming waits on its `can` verdict from `useVibe("bookings")`: a `Skeleton` inside an `aria-busy` wrapper while it resolves, and a sentence in the app's own words when booking is closed. For a visitor who has not signed in, the lead is `Sign in to confirm`, wired to `useViewer().requestLogin()`, and their choices stay in place. Sign-in is required here, unlike a local-first note, because a signed-out write stays on the device until sign-in: a booking made that way would never reach the practice or hold the slot against anyone else. Between the write and the live query catching up, the wizard shows a confirming `Skeleton` rather than the review again, so the lead can't book twice; cancelling the booking just made resets the wizard.
|
|
10
10
|
|
|
11
11
|
### `App.jsx`
|
|
12
12
|
```jsx
|
|
@@ -15,7 +15,7 @@ import { useFireproof } from "use-fireproof";
|
|
|
15
15
|
import { useViewer, useVibe } from "use-vibes";
|
|
16
16
|
import {
|
|
17
17
|
Badge,
|
|
18
|
-
|
|
18
|
+
IconTile,
|
|
19
19
|
Button,
|
|
20
20
|
Card,
|
|
21
21
|
Empty,
|
|
@@ -31,8 +31,8 @@ import {
|
|
|
31
31
|
Spacer,
|
|
32
32
|
Stack,
|
|
33
33
|
Text,
|
|
34
|
-
} from "@vibes.diy/
|
|
35
|
-
import { Confirm, Progress, RadioGroup, Toaster, toast } from "@vibes.diy/
|
|
34
|
+
} from "@vibes.diy/ui";
|
|
35
|
+
import { Confirm, Progress, RadioGroup, Toaster, toast } from "@vibes.diy/ui/interactive";
|
|
36
36
|
|
|
37
37
|
const SERVICES = [
|
|
38
38
|
{ id: "relax", name: "Relaxation massage", blurb: "A slow, full-body session to unwind.", minutes: 60, price: 80, icon: "sparkle" },
|
|
@@ -227,7 +227,7 @@ export default function App() {
|
|
|
227
227
|
}}
|
|
228
228
|
>
|
|
229
229
|
<Row gap={3} wrap={false} align="top">
|
|
230
|
-
<
|
|
230
|
+
<IconTile icon={s.icon} tone="orange" size="sm" />
|
|
231
231
|
<Stack gap={1}>
|
|
232
232
|
<Text>{s.name}</Text>
|
|
233
233
|
<Text size="sm" muted>
|
|
@@ -378,7 +378,7 @@ export default function App() {
|
|
|
378
378
|
</Stack>
|
|
379
379
|
<Card>{wizard}</Card>
|
|
380
380
|
</Grid>
|
|
381
|
-
<div className="
|
|
381
|
+
<div className="ui-toasts">
|
|
382
382
|
<Toaster />
|
|
383
383
|
</div>
|
|
384
384
|
</main>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-calendar.js","sourceRoot":"","sources":["../../jsr/llms/ui-calendar.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,gBAAgB,GAAc;IACzC,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,CAAC,eAAe,CAAC;IAC1B,KAAK,EAAE,gBAAgB;IACvB,WAAW,EAAE,uEAAuE;CACrF,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Calendar
|
|
2
2
|
|
|
3
3
|
An on-screen calendar of timed events: a studio's class timetable, a family's appointments, a club's practice schedule, a shared room's bookings for the week. Reach for it when the app shows a month at a glance and one day's agenda in time order, with the free gaps between events and a line where "now" falls, and lets people add and remove events. This is the calendar people look at inside the app; a subscribable phone-calendar feed (webcal or `.ics`) is a different job, served from the backend. Each event is its own document, so everyone who opens the app sees the same schedule.
|
|
4
4
|
|
|
5
|
-
Built from @vibes.diy/
|
|
5
|
+
Built from @vibes.diy/ui components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
|
7
7
|
## The block
|
|
8
8
|
|
|
@@ -13,8 +13,8 @@ One view with one job: see what is on and add to it. The `Heading` and a muted l
|
|
|
13
13
|
import React, { useEffect, useState } from "react";
|
|
14
14
|
import { useFireproof } from "use-fireproof";
|
|
15
15
|
import { useViewer, useVibe } from "use-vibes";
|
|
16
|
-
import { Badge, Button, Card, Empty, Field, Grid, Heading, Icon, IconButton, Input, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/
|
|
17
|
-
import { Confirm, Dialog, Select, Toaster, toast } from "@vibes.diy/
|
|
16
|
+
import { Badge, Button, Card, Empty, Field, Grid, Heading, Icon, IconButton, Input, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/ui";
|
|
17
|
+
import { Confirm, Dialog, Select, Toaster, toast } from "@vibes.diy/ui/interactive";
|
|
18
18
|
|
|
19
19
|
const pad = (n) => String(n).padStart(2, "0");
|
|
20
20
|
// Dates are kept as local YYYY-MM-DD strings, so an event never drifts a day across time zones.
|
|
@@ -332,7 +332,7 @@ export default function App() {
|
|
|
332
332
|
</Stack>
|
|
333
333
|
</Card>
|
|
334
334
|
</Stack>
|
|
335
|
-
<div className="
|
|
335
|
+
<div className="ui-toasts">
|
|
336
336
|
<Toaster />
|
|
337
337
|
</div>
|
|
338
338
|
</main>
|
package/llms/ui-chat.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-chat.js","sourceRoot":"","sources":["../../jsr/llms/ui-chat.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,CAAC,WAAW,CAAC;IACtB,KAAK,EAAE,YAAY;IACnB,WAAW,EAAE,4DAA4D;CAC1E,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Chat
|
|
2
2
|
|
|
3
3
|
A group conversation split into rooms: a crew's chat with a room per trip, a band's thread per song, a household's rooms for groceries and plans, a class's channel per project. Reach for it whenever the app's core is people sending each other short messages that read top to bottom as they arrive. Rooms and messages persist and arrive live, so everyone in the app sees a new message as soon as it is sent, on every device.
|
|
4
4
|
|
|
5
|
-
Built from @vibes.diy/
|
|
5
|
+
Built from @vibes.diy/ui components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
|
7
7
|
## The block
|
|
8
8
|
|
|
@@ -13,8 +13,8 @@ Two views, one job each. The room list opens with the `Heading` and a muted coun
|
|
|
13
13
|
import React, { useEffect, useRef, useState } from "react";
|
|
14
14
|
import { useFireproof } from "use-fireproof";
|
|
15
15
|
import { useViewer, useVibe } from "use-vibes";
|
|
16
|
-
import { Button, Card, Empty, Field, Heading, Icon, IconButton, Input, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/
|
|
17
|
-
import { ScrollArea } from "@vibes.diy/
|
|
16
|
+
import { Button, Card, Empty, Field, Heading, Icon, IconButton, Input, Row, RowCard, Skeleton, Stack, Text } from "@vibes.diy/ui";
|
|
17
|
+
import { ScrollArea } from "@vibes.diy/ui/interactive";
|
|
18
18
|
|
|
19
19
|
const when = (ms) => new Date(ms).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
|
|
20
20
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-contact.js","sourceRoot":"","sources":["../../jsr/llms/ui-contact.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,CAAC,cAAc,CAAC;IACzB,KAAK,EAAE,eAAe;IACtB,WAAW,EAAE,mEAAmE;CACjF,CAAC"}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Contact
|
|
2
2
|
|
|
3
3
|
A get-in-touch section where someone leaves their name, email, a topic and a message for the people behind the app: a photography studio's enquiry form, a community garden's question box, a band's booking request. Reach for it whenever the app's job is to collect a note and say clearly that it arrived. Every message persists as its own document, so the team can read and answer them later (the inbox block is the reading side).
|
|
4
4
|
|
|
5
|
-
Built from @vibes.diy/
|
|
5
|
+
Built from @vibes.diy/ui components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
|
7
7
|
## The block
|
|
8
8
|
|
|
9
|
-
One view with one job: send a note. A `Grid cols="sidebar"` puts the pitch beside the form: an `info` `Badge` with the reply time, an `Eyebrow`, the `Heading` and a muted line, then two tight `Card`s that tilt, each fronted by a small `
|
|
9
|
+
One view with one job: send a note. A `Grid cols="sidebar"` puts the pitch beside the form: an `info` `Badge` with the reply time, an `Eyebrow`, the `Heading` and a muted line, then two tight `Card`s that tilt, each fronted by a small `IconTile` (`info` mail, `idle` clock). The form sits on its own `Card`: name and email `Input`s, a topic `Select` and a message `Textarea`, each in a `Field`. It is checked in plain state on submit, with each error on its own `Field`, its control `invalid` and focus moved to the first one. `Send message` is the view's one lead and shows `loading` while the write lands. Each message is one document, stamped with the sender's handle when they are signed in. The form waits on its `can` verdict from `useVibe("contact")`: a `Skeleton` inside an `aria-busy` wrapper while it resolves, a `Sign in to send a message` lead wired to `requestLogin()` when sending is closed to a signed-out visitor, and a sentence in the app's own words when it is closed to someone already signed in. Where `access.js` lets a signed-out visitor write, they can still send; their note is kept on this device until they sign in. So their confirmation says that honestly (`Your note is waiting`), and its lead is `Sign in to send it`, wired to `useViewer().requestLogin()`. A signed-in sender sees `Message sent` in an `Empty`, with a quiet `Send another message`.
|
|
10
10
|
|
|
11
11
|
### `App.jsx`
|
|
12
12
|
```jsx
|
|
13
13
|
import React, { useRef, useState } from "react";
|
|
14
14
|
import { useFireproof } from "use-fireproof";
|
|
15
15
|
import { useViewer, useVibe } from "use-vibes";
|
|
16
|
-
import { Badge,
|
|
17
|
-
import { Select } from "@vibes.diy/
|
|
16
|
+
import { Badge, IconTile, Button, Card, Empty, Eyebrow, Field, Grid, Heading, Input, Row, Skeleton, Stack, Text, Textarea } from "@vibes.diy/ui";
|
|
17
|
+
import { Select } from "@vibes.diy/ui/interactive";
|
|
18
18
|
|
|
19
19
|
const TOPICS = [
|
|
20
20
|
{ value: "booking", label: "Book a shoot" },
|
|
@@ -194,7 +194,7 @@ export default function App() {
|
|
|
194
194
|
</Stack>
|
|
195
195
|
<Card variant="tight" motion="tilt-left">
|
|
196
196
|
<Row gap={3} wrap={false} align="top">
|
|
197
|
-
<
|
|
197
|
+
<IconTile icon="mail" tone="info" size="sm" />
|
|
198
198
|
<Stack gap={1}>
|
|
199
199
|
<Text>Prefer email?</Text>
|
|
200
200
|
<Text size="sm" muted>
|
|
@@ -205,7 +205,7 @@ export default function App() {
|
|
|
205
205
|
</Card>
|
|
206
206
|
<Card variant="tight" motion="tilt-right">
|
|
207
207
|
<Row gap={3} wrap={false} align="top">
|
|
208
|
-
<
|
|
208
|
+
<IconTile icon="clock" tone="idle" size="sm" />
|
|
209
209
|
<Stack gap={1}>
|
|
210
210
|
<Text>Read by a person</Text>
|
|
211
211
|
<Text size="sm" muted>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-course.js","sourceRoot":"","sources":["../../jsr/llms/ui-course.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,CAAC,aAAa,CAAC;IACxB,KAAK,EAAE,cAAc;IACrB,WAAW,EAAE,4DAA4D;CAC1E,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Course
|
|
2
2
|
|
|
3
3
|
A course outline someone works through lesson by lesson: a beginner pottery class, new staff training at a café, a study plan for an exam, a coding bootcamp's first week. Reach for it whenever the app's core is an ordered set of lessons, each with a rough length, that a person marks complete while a bar shows how far along they are. The lessons and each person's completions persist, so progress is waiting on the next visit and on every device, and every learner keeps their own.
|
|
4
4
|
|
|
5
|
-
Built from @vibes.diy/
|
|
5
|
+
Built from @vibes.diy/ui components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
|
7
7
|
## The block
|
|
8
8
|
|
|
9
|
-
Two views, one job each. The outline opens with the `Heading` and a muted count beside a quiet `Add lesson` button that opens a `Dialog` with the lesson form. A `Card` holds the person's progress: a `Progress` bar toned `up`, the percent and minutes left in `Text`,
|
|
9
|
+
Two views, one job each. The outline opens with the `Heading` and a muted count beside a quiet `Add lesson` button that opens a `Dialog` with the lesson form. A `Card` holds the person's progress: a `Progress` bar toned `up`, the percent and minutes left in `Text`, an `IconTile` (`info` target while lessons remain, `up` trophy once they are all done) and a `Continue` button, the outline's one lead, that opens the next unfinished lesson. Each lesson is a clickable `RowCard` with a small `IconTile`, a muted line for its kind and length, its title and a `Badge` (`up` done, `idle` to do); an `Empty` stands in before the first lesson. Opening a lesson swaps in the lesson view: a quiet `IconButton` to go back, the kind as an `info` `Badge`, the title as the `Heading`, `Metric`s for the time and the lesson's place in the course, and `Mark complete` as that view's lead (or, once done, a quiet `Mark not done` beside a `Next lesson` lead). A completion is its own document with a deterministic `_id` per lesson and person, so each learner's progress is theirs and marking twice lands on one document. Every write waits on its `can` verdict from `useVibe("course")`: the lesson form and the completion buttons show a `Skeleton` inside an `aria-busy` wrapper while the verdict resolves and a sentence in the app's own words when that write is closed to this visitor. Progress belongs to a person, so a visitor who has not signed in sees a `Sign in to track progress` button wired to `useViewer().requestLogin()` instead of the completion buttons.
|
|
10
10
|
|
|
11
11
|
### `App.jsx`
|
|
12
12
|
```jsx
|
|
@@ -15,7 +15,7 @@ import { useFireproof } from "use-fireproof";
|
|
|
15
15
|
import { useViewer, useVibe } from "use-vibes";
|
|
16
16
|
import {
|
|
17
17
|
Badge,
|
|
18
|
-
|
|
18
|
+
IconTile,
|
|
19
19
|
Button,
|
|
20
20
|
Card,
|
|
21
21
|
Empty,
|
|
@@ -32,8 +32,8 @@ import {
|
|
|
32
32
|
Spacer,
|
|
33
33
|
Stack,
|
|
34
34
|
Text,
|
|
35
|
-
} from "@vibes.diy/
|
|
36
|
-
import { Dialog, Progress, Select, Toaster, toast } from "@vibes.diy/
|
|
35
|
+
} from "@vibes.diy/ui";
|
|
36
|
+
import { Dialog, Progress, Select, Toaster, toast } from "@vibes.diy/ui/interactive";
|
|
37
37
|
|
|
38
38
|
const KINDS = [
|
|
39
39
|
{ value: "Lesson", label: "Lesson" },
|
|
@@ -247,7 +247,7 @@ export default function App() {
|
|
|
247
247
|
</Row>
|
|
248
248
|
)}
|
|
249
249
|
</Stack>
|
|
250
|
-
<
|
|
250
|
+
<IconTile icon={finished ? "trophy" : "target"} tone={finished ? "up" : "info"} size="md" />
|
|
251
251
|
</Row>
|
|
252
252
|
</Card>
|
|
253
253
|
)}
|
|
@@ -263,7 +263,7 @@ export default function App() {
|
|
|
263
263
|
return (
|
|
264
264
|
<RowCard key={lesson._id} onClick={() => setOpenId(lesson._id)}>
|
|
265
265
|
<Row gap={3} wrap={false}>
|
|
266
|
-
<
|
|
266
|
+
<IconTile icon={done ? "ok" : lesson.kind === "Quiz" ? "wand" : "play"} tone={done ? "up" : "idle"} size="sm" />
|
|
267
267
|
<Stack gap={1}>
|
|
268
268
|
<Text size="sm" muted>
|
|
269
269
|
{lesson.kind} · {MINUTES.format(lesson.minutes)}
|
|
@@ -280,7 +280,7 @@ export default function App() {
|
|
|
280
280
|
)}
|
|
281
281
|
</Stack>
|
|
282
282
|
)}
|
|
283
|
-
<div className="
|
|
283
|
+
<div className="ui-toasts">
|
|
284
284
|
<Toaster />
|
|
285
285
|
</div>
|
|
286
286
|
</main>
|
package/llms/ui-crm.d.ts
ADDED
package/llms/ui-crm.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-crm.js","sourceRoot":"","sources":["../../jsr/llms/ui-crm.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,WAAW,GAAc;IACpC,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,KAAK,EAAE,WAAW;IAClB,WAAW,EAAE,kEAAkE;CAChF,CAAC"}
|