your-ai-workflow-firebase-os 1.2.39 → 1.2.40

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "your-ai-workflow-firebase-os",
3
- "version": "1.2.39",
3
+ "version": "1.2.40",
4
4
  "description": "Your AI Firebase — a complete Firebase-powered admin app in one React component.",
5
5
  "type": "module",
6
6
  "main": "dist/your-ai-workflow-firebase-os.cjs.js",
@@ -310,7 +310,9 @@ stops the build with one sentence that says the fix.
310
310
  preset and no matching content file (the page would render empty — the
311
311
  error names the exact \`*Content.tsx\` to create); a \`<style>\` tag in a
312
312
  content file (global CSS — it restyles and re-pads every page of the app,
313
- style with theme classes instead).
313
+ style with theme classes instead); a \`*Content.tsx\` or \`*.config.ts\`
314
+ saved anywhere except directly in its own folder — a subfolder, another
315
+ directory — is invisible to the app, so the build stops and names the move.
314
316
  - A hand-written form — a \`<form>\` or an \`onSubmit\` in a content file with
315
317
  no \`<ContactPopup />\` — prints a warning, because its entries never reach
316
318
  the Inbox and never show on the Forms screen. So does a hard-coded colour
@@ -701,20 +703,13 @@ starting layout, its form), then pasted the row's sentence and finished it:
701
703
  > already made and it is already in the menu — do not create a page, a web
702
704
  > address or a settings file for it, and do not edit any other file.
703
705
  > Write one file:
704
- > src/your-ai-workflow-firebase-os/microcomponents/ClientOnboardingContent.tsx,
706
+ > src/your-ai-workflow-firebase-os/microcomponents/OnboardingContent.tsx,
705
707
  > with a default export. That file is what the page shows.
706
- > The page already starts from the board layout — the heading and the saving
707
- > are already built and stay on the page. Your file draws only what goes
708
- > inside the panel.
709
- > Your component receives everything it needs as props: ({ config, actions })
710
- > — actions.tasks and actions.categories hold the saved items;
711
- > actions.saveTask(id, data), actions.deleteTask(id),
712
- > actions.saveCategory(id, data) and actions.deleteCategory(id) change them;
713
- > actions.openInlineEditor(categoryId, item) opens the built-in editor;
714
- > actions.user is the signed-in person, and every item you save must include
715
- > uid: actions.user.uid. Read and change data ONLY through these props — do
716
- > not import firebase and do not write your own loading, saving or uploading
717
- > code.
708
+ > Make it match the rest of my app: style with the app's own theme styles so
709
+ > it looks right in light and dark. Do not pick your own colors.
710
+ > Until your file exists the page shows a ready-made board layout. Treat it
711
+ > as a reference, not a rule — your file replaces everything inside the
712
+ > page, so build the whole thing the way I describe below.
718
713
  > Here is what I would like on it: columns, in this order: To do, In
719
714
  > progress, Done. Each card has a client name (short text), a contact email,
720
715
  > a start date and a short note (long text). Anyone on the team can add a
@@ -724,19 +719,20 @@ starting layout, its form), then pasted the row's sentence and finished it:
724
719
 
725
720
  Every line is a decision already made. The audience, the web address
726
721
  (\`route\`), the name (\`tabName\` / \`pageName\`), the heading (\`tabTitle\` /
727
- \`pageTitle\`) and "already starts from the ... layout" (\`template\`) were set
728
- on the Pages screen — read them from the \`config\` your content file receives,
729
- and never write them again. When the sentence lists props, they are real: the
730
- layout renders your component with exactly those, so a content file that
731
- ignores them and opens its own Firestore connection is wrong even if it runs. THE FILE NAME RULE: the content file is the page's
732
- name in PascalCase plus \`Content.tsx\` (a page called "Client onboarding" ->
733
- \`ClientOnboardingContent.tsx\`); use exactly the name in the request, or the
734
- page never finds your file. "No file uploads" means draw no upload control;
735
- the "button at the top" is yours to draw inside the content; and a question's
736
- kind in brackets — short text, long text, email, phone, number, money, yes-no,
737
- choose one — is the input you render (\`text\`, \`textarea\`, \`email\`, \`tel\`,
738
- \`number\`, \`currency\`, \`checkbox\`, \`select\`). "Build only this" means exactly
739
- that. Ask nothing; build it in one turn.
722
+ \`pageTitle\`) and the starting layout (\`template\`) were set on the Pages
723
+ screen — read them from the \`config\` your content file receives, and never
724
+ write them again. Your component also receives \`actions\` (\`records\`,
725
+ \`saveRecord\`, \`updateRecord\`, \`deleteRecord\`, \`uploadFile\`, \`user\`, and the
726
+ rest listed under presets below) — read and change data ONLY through those,
727
+ never by importing firebase yourself. THE FILE NAME RULE: write EXACTLY the
728
+ file path the request names, letter for letter — the page is wired to that
729
+ one name, and a file under any other name or folder is never found. "No file
730
+ uploads" means draw no upload control; the "button at the top" is yours to
731
+ draw inside the content; and a question's kind in brackets — short text, long
732
+ text, email, phone, number, money, yes-no, choose one — is the input you
733
+ render (\`text\`, \`textarea\`, \`email\`, \`tel\`, \`number\`, \`currency\`,
734
+ \`checkbox\`, \`select\`). "Build only this" means exactly that. Ask nothing;
735
+ build it in one turn.
740
736
 
741
737
  ### A form
742
738
 
@@ -887,19 +883,20 @@ add / upload / delete — you then write the microcomponent that fills it
887
883
 
888
884
  A preset (\`board\`, \`calendar\`, \`table\`, \`drive\`) is only a starting point:
889
885
  it renders a working board / calendar / table / file library straight away when
890
- there is NO content file. As soon as you add a content file, it REPLACES what the preset
891
- draws inside the panel — you keep the preset's title, header and data hooks
892
- (\`board\`: \`tasks\`, \`categories\`, \`saveTask(id, data)\`, \`deleteTask\`,
893
- \`saveCategory\`, \`deleteCategory\`, \`user\`; \`calendar\`: \`events\`,
894
- \`saveEvent\`, \`deleteEvent\`, \`openAddModal\`, \`openEditModal\`, \`currentUser\`;
895
- \`table\`: \`tables\`, \`activeTable\`, \`saveTable\`, \`deleteTable\`, \`updateCell\`,
896
- \`addRow\`, \`addColumn\`, \`user\`; \`drive\`: \`files\`, \`loading\`, \`uploadFile\`,
897
- \`deleteFile\`, \`user\`), and you draw the columns, cards or grid yourself. So when the owner wants their own fields,
898
- stages or views on "something like the board", pick \`template: 'board'\` for
899
- its data and build the board UI in the content file. Never treat a preset as
900
- the finished page — they described what they want, so build that.
901
-
902
- Whatever you save through those hooks, include \`uid: user.uid\` in the data:
886
+ there is NO content file. As soon as you add a content file, the page renders
887
+ YOUR file instead of the preset — the whole panel, its buttons included, is
888
+ yours to draw, and your component receives the same \`actions\` as a
889
+ from-scratch page (\`records\`, \`loading\`, \`saveRecord\`, \`updateRecord\`,
890
+ \`deleteRecord\`, \`startEdit\`, \`confirmDelete\`, \`uploadFile\`, \`openAddForm\`,
891
+ \`setAddForm\`, \`setFileHandler\`, \`user\` — every record you save must include
892
+ \`uid: actions.user.uid\`). The preset is a REFERENCE for what to build, never
893
+ a frame you build inside: when the owner wants their own fields, stages or
894
+ views on "something like the board", look at the board for the shape and
895
+ build the whole board UI in the content file with those \`actions\`. Never
896
+ treat a preset as the finished page — they described what they want, so
897
+ build that.
898
+
899
+ Whatever you save through those actions, include \`uid: user.uid\` in the data:
903
900
  on Your-team pages only the person who created a record (or an admin) may edit
904
901
  or delete it, and a record without \`uid\` can only ever be changed by an admin.
905
902
 
@@ -931,12 +928,12 @@ useEffect(() => {
931
928
  if (userRole !== 'admin') return; // only admins may read the Inbox
932
929
  return onSnapshot(collection(db, 'user_submissions'), snap => {
933
930
  snap.docs.forEach(d => {
934
- if (tasks.some((t: any) => t.sourceId === d.id)) return; // already imported
931
+ if (actions.records.some((r: any) => r.sourceId === d.id)) return; // already imported
935
932
  const s = d.data();
936
- saveTask('', { ...s, sourceId: d.id, stage: 'Prospect', uid: user!.uid, createdAt: Date.now() });
933
+ actions.saveRecord({ ...s, sourceId: d.id, stage: 'Prospect', uid: user!.uid });
937
934
  });
938
935
  });
939
- }, [userRole, tasks.length]);
936
+ }, [userRole, actions.records.length]);
940
937
  \`\`\`
941
938
 
942
939
  Never write to \`user_submissions\` or \`user_requests\` from a page, and never
@@ -65,8 +65,10 @@ export const themeConfig = {
65
65
  foreground: '#1e1b4b', // Primary text color
66
66
 
67
67
  accent: '#7c3aed', // Main branding color (Purple)
68
- panelBg: 'rgba(255, 255, 255, 0.70)', // Card/Panel background
69
- panelBorder: 'rgba(124, 58, 237, 0.08)', // Card/Panel borders
68
+ // A faint accent wash rather than white-on-white: inner cards were
69
+ // invisible against the page in light mode. Kept quiet on purpose.
70
+ panelBg: 'rgba(124, 58, 237, 0.04)', // Card/Panel background
71
+ panelBorder: 'rgba(124, 58, 237, 0.15)', // Card/Panel borders
70
72
 
71
73
  buttonGradient: ['#5b21b6', '#a78bfa'], // [Start, End]
72
74
  secondaryButton: {
package/src/index.css CHANGED
@@ -75,8 +75,10 @@ input[type=number] {
75
75
  --accent-deep: #6d28d9;
76
76
  /* violet-700 */
77
77
 
78
- --panel-bg: rgba(255, 255, 255, 0.7);
79
- --panel-border: color-mix(in srgb, var(--accent-color) 8%, transparent);
78
+ /* A faint accent wash, not white-on-white: inner cards were invisible
79
+ against the page in light mode. Kept quiet on purpose. */
80
+ --panel-bg: color-mix(in srgb, var(--accent-color) 4%, transparent);
81
+ --panel-border: color-mix(in srgb, var(--accent-color) 15%, transparent);
80
82
 
81
83
  --button-bg: linear-gradient(135deg, #5b21b6 0%, #a78bfa 100%);
82
84
  --button-fg: #ffffff;
@@ -192,6 +194,13 @@ h3,
192
194
  0 2px 6px rgba(24, 16, 64, 0.07);
193
195
  }
194
196
 
197
+ /* An open drop-down. Deliberately NOT .glow-focus: the 25px halo read as a
198
+ spotlight on what is just a list being open, and it was sliced off by any
199
+ panel animating its height nearby. An inset ring cannot be clipped. */
200
+ .select-open {
201
+ box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent-color) 22%, transparent);
202
+ }
203
+
195
204
  .glow-focus:focus-within {
196
205
  box-shadow: 0 0 25px var(--glow-color, var(--primary-glow));
197
206
  border-color: var(--accent-color);
@@ -224,27 +233,28 @@ h3,
224
233
  }
225
234
 
226
235
  /*
227
- * Fields in the admin consoles keep the accent focus, but tight. A console
228
- * is panels inside panels, and the ones that open and close animate their
229
- * height behind overflow: hidden — so the 15-25px halo above spills past the
230
- * field and gets sliced straight off at the panel edge. A 3px ring sits well
231
- * inside the panel's own padding: softer to look at, and nothing can clip
232
- * it. `.console-field` goes on the box itself; `.console-select` goes on the
236
+ * Fields in the admin consoles keep the accent focus, but tight — and INSET.
237
+ * A console is panels inside panels, and the ones that open and close
238
+ * animate their height behind overflow: hidden, so anything drawn OUTSIDE
239
+ * the field's own box — a halo, even a 3px outer ring — gets sliced off at
240
+ * whichever panel edge is nearest. An inset ring is drawn on the inside of
241
+ * the field's border, so no container can ever clip it, anywhere.
242
+ * `.console-field` goes on the box itself; `.console-select` goes on the
233
243
  * CustomSelect wrapper, whose bordered box is the trigger inside it.
234
244
  */
235
245
  .console-field:focus,
236
246
  .console-field:focus-within,
237
- .console-select .glow-focus:focus-within {
238
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 15%, transparent) !important;
247
+ .console-select .select-open {
248
+ box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent-color) 22%, transparent) !important;
239
249
  border-color: var(--accent-color) !important;
240
250
  outline: none;
241
- transform: none;
251
+ transform: none !important;
242
252
  }
243
253
 
244
254
  /* A field that is refusing what was typed stays red while it is focused. */
245
255
  .console-field.is-invalid:focus,
246
256
  .console-field.is-invalid:focus-within {
247
- box-shadow: 0 0 0 3px color-mix(in srgb, #ef4444 18%, transparent) !important;
257
+ box-shadow: inset 0 0 0 2px color-mix(in srgb, #ef4444 25%, transparent) !important;
248
258
  border-color: #ef4444 !important;
249
259
  }
250
260