@vertebr/react 0.5.0 → 0.6.0

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.
Files changed (75) hide show
  1. package/dist/components/admin/AdminContent.d.ts +11 -2
  2. package/dist/components/admin/AdminContent.d.ts.map +1 -1
  3. package/dist/components/admin/AdminContent.js +35 -10
  4. package/dist/components/admin/AdminHeader.d.ts +3 -1
  5. package/dist/components/admin/AdminHeader.d.ts.map +1 -1
  6. package/dist/components/admin/AdminHeader.js +12 -3
  7. package/dist/components/admin/PagePreviewPane.d.ts +14 -0
  8. package/dist/components/admin/PagePreviewPane.d.ts.map +1 -0
  9. package/dist/components/admin/PagePreviewPane.js +121 -0
  10. package/dist/components/admin/VertebrAdmin.d.ts +1 -1
  11. package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
  12. package/dist/components/admin/VertebrAdmin.js +123 -41
  13. package/dist/components/admin/routes.d.ts +21 -0
  14. package/dist/components/admin/routes.d.ts.map +1 -0
  15. package/dist/components/admin/routes.js +170 -0
  16. package/dist/components/admin/types.d.ts +7 -0
  17. package/dist/components/admin/types.d.ts.map +1 -1
  18. package/dist/components/config/VisibilityEye.d.ts +12 -0
  19. package/dist/components/config/VisibilityEye.d.ts.map +1 -1
  20. package/dist/components/config/VisibilityEye.js +12 -4
  21. package/dist/components/config/form/ConfigField.d.ts +5 -3
  22. package/dist/components/config/form/ConfigField.d.ts.map +1 -1
  23. package/dist/components/config/form/ConfigField.js +7 -3
  24. package/dist/components/config/form/ConfigForm.d.ts +1 -1
  25. package/dist/components/config/form/ConfigForm.d.ts.map +1 -1
  26. package/dist/components/config/form/ConfigForm.js +5 -1
  27. package/dist/components/config/form/RecordConfigForm.d.ts +1 -1
  28. package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -1
  29. package/dist/components/config/form/RecordConfigForm.js +2 -2
  30. package/dist/components/config/form/SettingsConfigForm.d.ts +3 -3
  31. package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -1
  32. package/dist/components/config/form/SettingsConfigForm.js +7 -2
  33. package/dist/components/config/form/helpers/fields.d.ts +2 -1
  34. package/dist/components/config/form/helpers/fields.d.ts.map +1 -1
  35. package/dist/components/config/form/helpers/fields.js +4 -0
  36. package/dist/components/config/form/types.d.ts +6 -1
  37. package/dist/components/config/form/types.d.ts.map +1 -1
  38. package/dist/components/fonts/FontFaceInjector.d.ts +9 -0
  39. package/dist/components/fonts/FontFaceInjector.d.ts.map +1 -0
  40. package/dist/components/fonts/FontFaceInjector.js +28 -0
  41. package/dist/components/fonts/FontLibraryBoard.d.ts +15 -0
  42. package/dist/components/fonts/FontLibraryBoard.d.ts.map +1 -0
  43. package/dist/components/fonts/FontLibraryBoard.js +41 -0
  44. package/dist/components/fonts/FontPickerField.d.ts +16 -0
  45. package/dist/components/fonts/FontPickerField.d.ts.map +1 -0
  46. package/dist/components/fonts/FontPickerField.js +49 -0
  47. package/dist/components/fonts/FontPreviewModal.d.ts +18 -0
  48. package/dist/components/fonts/FontPreviewModal.d.ts.map +1 -0
  49. package/dist/components/fonts/FontPreviewModal.js +57 -0
  50. package/dist/components/fonts/FontPreviewSample.d.ts +8 -0
  51. package/dist/components/fonts/FontPreviewSample.d.ts.map +1 -0
  52. package/dist/components/fonts/FontPreviewSample.js +13 -0
  53. package/dist/components/fonts/GoogleFontsBrowser.d.ts +8 -0
  54. package/dist/components/fonts/GoogleFontsBrowser.d.ts.map +1 -0
  55. package/dist/components/fonts/GoogleFontsBrowser.js +49 -0
  56. package/dist/components/resources/ResourceCell.js +3 -2
  57. package/dist/components/resources/ResourceTable.d.ts +1 -1
  58. package/dist/components/resources/ResourceTable.d.ts.map +1 -1
  59. package/dist/components/resources/ResourceTable.js +123 -5
  60. package/dist/hooks/useVertebrControls.d.ts +10 -1
  61. package/dist/hooks/useVertebrControls.d.ts.map +1 -1
  62. package/dist/hooks/useVertebrControls.js +32 -3
  63. package/dist/index.d.ts +3 -1
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +3 -2
  66. package/dist/styles/base.css +3 -3
  67. package/dist/styles/font-library.css +401 -0
  68. package/dist/styles/form.css +89 -3
  69. package/dist/styles/index.css +3 -1
  70. package/dist/styles/main.css +1 -1
  71. package/dist/styles/page-preview.css +208 -0
  72. package/dist/styles/panel.css +7 -2
  73. package/dist/styles/states.css +6 -3
  74. package/dist/styles/table.css +18 -0
  75. package/package.json +1 -1
@@ -1,14 +1,19 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from "react";
3
- import { createVertebrClient } from "@vertebr/client";
3
+ import { createVertebrClient, isVertebrPreviewMode, postVertebrPreviewReady, subscribeVertebrPreviewDraft, } from "@vertebr/client";
4
4
  const ControlsContext = createContext(null);
5
5
  /**
6
6
  * Loads all public Vertebr controls for the storefront once and shares them.
7
+ * When the URL has `?vertebrPreview=1`, also merges live drafts from the
8
+ * admin iframe parent (host still renders).
7
9
  */
8
- export function VertebrControlsProvider({ apiBase = "/admin/api", environment, children, }) {
10
+ export function VertebrControlsProvider({ apiBase = "/admin/api", environment, enablePreview, children, }) {
9
11
  const [controls, setControls] = useState({});
12
+ const [drafts, setDrafts] = useState({});
10
13
  const [loading, setLoading] = useState(true);
11
14
  const [error, setError] = useState(null);
15
+ const previewEnabled = enablePreview ??
16
+ (typeof window !== "undefined" && isVertebrPreviewMode());
12
17
  const client = useMemo(() => createVertebrClient({
13
18
  apiBase,
14
19
  getEnvironment: () => environment,
@@ -31,7 +36,31 @@ export function VertebrControlsProvider({ apiBase = "/admin/api", environment, c
31
36
  useEffect(() => {
32
37
  void load();
33
38
  }, [load]);
34
- const value = useMemo(() => ({ environment, controls, loading, error, refresh }), [environment, controls, loading, error, refresh]);
39
+ useEffect(() => {
40
+ if (!previewEnabled)
41
+ return;
42
+ postVertebrPreviewReady();
43
+ return subscribeVertebrPreviewDraft((controlId, value) => {
44
+ setDrafts((current) => ({ ...current, [controlId]: value }));
45
+ });
46
+ }, [previewEnabled]);
47
+ const merged = useMemo(() => {
48
+ if (!previewEnabled || Object.keys(drafts).length === 0)
49
+ return controls;
50
+ const next = { ...controls };
51
+ for (const [id, value] of Object.entries(drafts)) {
52
+ next[id] = { ...(controls[id] ?? {}), ...value };
53
+ }
54
+ return next;
55
+ }, [controls, drafts, previewEnabled]);
56
+ const value = useMemo(() => ({
57
+ environment,
58
+ controls: merged,
59
+ loading,
60
+ error,
61
+ refresh,
62
+ preview: previewEnabled,
63
+ }), [environment, merged, loading, error, refresh, previewEnabled]);
35
64
  return (_jsx(ControlsContext.Provider, { value: value, children: children }));
36
65
  }
37
66
  function useControlsContext() {
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export { VertebrAdmin } from "./components/admin/VertebrAdmin";
2
2
  export type { VertebrAdminProps } from "./components/admin/VertebrAdmin";
3
3
  export { MetricsBoard } from "./components/metrics/MetricsBoard";
4
4
  export { GalleryBoard } from "./components/gallery/GalleryBoard";
5
+ export { FontLibraryBoard } from "./components/fonts/FontLibraryBoard";
6
+ export { FontPickerField } from "./components/fonts/FontPickerField";
5
7
  export { EmailsBoard } from "./components/emails/EmailsBoard";
6
8
  export type { EmailsBoardProps } from "./components/emails/EmailsBoard";
7
9
  export type { EmailRecipientOption } from "./components/emails/EmailRecipientSelect";
@@ -20,7 +22,7 @@ export { useVertebrTheme } from "./hooks/useVertebrTheme";
20
22
  export type { VbTheme } from "./hooks/useVertebrTheme";
21
23
  export { VertebrControlsProvider, useVertebrConfig, useVertebrControls, } from "./hooks/useVertebrControls";
22
24
  export type { VertebrControlsProviderProps } from "./hooks/useVertebrControls";
23
- export { createVertebrClient, VERTEBR_ENV_HEADER, renderMarkdown, } from "@vertebr/client";
25
+ export { createVertebrClient, VERTEBR_ENV_HEADER, renderMarkdown, isVertebrPreviewMode, getVertebrPreviewControlId, buildVertebrPreviewUrl, } from "@vertebr/client";
24
26
  export { VertebrMarkdown } from "@vertebr/client/react";
25
27
  export type { VertebrMarkdownProps } from "@vertebr/client/react";
26
28
  export { createVertebrCatalog, catalogHref, catalogMatch, } from "@vertebr/client";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,YAAY,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AACrF,YAAY,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,YAAY,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACtF,YAAY,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAG/E,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,WAAW,EACX,SAAS,EACT,WAAW,EACX,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACV,WAAW,EACX,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,cAAc,EACd,kBAAkB,GACnB,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export { VertebrAdmin } from "./components/admin/VertebrAdmin";
2
2
  export { MetricsBoard } from "./components/metrics/MetricsBoard";
3
3
  export { GalleryBoard } from "./components/gallery/GalleryBoard";
4
+ export { FontLibraryBoard } from "./components/fonts/FontLibraryBoard";
5
+ export { FontPickerField } from "./components/fonts/FontPickerField";
4
6
  export { EmailsBoard } from "./components/emails/EmailsBoard";
5
7
  export { ResourcePanel, ResourceTable } from "./components/resources/ResourceTable";
6
8
  export { ThemeToggle } from "./components/theme/ThemeToggle";
@@ -10,8 +12,7 @@ export { isDescriptionField, descriptionStats, applyMarkdown, } from "./lib/desc
10
12
  export { EnvSelect } from "./components/env/EnvSelect";
11
13
  export { useVertebrTheme } from "./hooks/useVertebrTheme";
12
14
  export { VertebrControlsProvider, useVertebrConfig, useVertebrControls, } from "./hooks/useVertebrControls";
13
- // Re-export the framework-agnostic client for convenience.
14
- export { createVertebrClient, VERTEBR_ENV_HEADER, renderMarkdown, } from "@vertebr/client";
15
+ export { createVertebrClient, VERTEBR_ENV_HEADER, renderMarkdown, isVertebrPreviewMode, getVertebrPreviewControlId, buildVertebrPreviewUrl, } from "@vertebr/client";
15
16
  export { VertebrMarkdown } from "@vertebr/client/react";
16
17
  export { createVertebrCatalog, catalogHref, catalogMatch, } from "@vertebr/client";
17
18
  export { VertebrCatalogProvider, useVertebrCatalog, useVertebrCatalogItem, } from "@vertebr/client/react";
@@ -21,9 +21,9 @@ html:has(.vertebr-error) body {
21
21
  position: relative;
22
22
  z-index: 1;
23
23
  box-sizing: border-box;
24
- height: 100vh;
25
- max-height: 100vh;
26
- min-height: 100vh;
24
+ height: 100dvh;
25
+ max-height: 100dvh;
26
+ min-height: 100dvh;
27
27
  width: 100%;
28
28
  display: grid;
29
29
  grid-template-columns: var(--vb-sidebar-width) 1fr;
@@ -0,0 +1,401 @@
1
+ /* ── Font library ─────────────────────────────────────── */
2
+
3
+ .vertebr-font-library {
4
+ flex: 1 1 auto;
5
+ min-height: 0;
6
+ display: flex;
7
+ flex-direction: column;
8
+ overflow: hidden;
9
+ }
10
+
11
+ .vertebr-font-library-head-actions {
12
+ display: flex;
13
+ align-items: center;
14
+ gap: 0.75rem;
15
+ }
16
+
17
+ .vertebr-font-library-body {
18
+ flex: 1 1 auto;
19
+ min-height: 0;
20
+ overflow: auto;
21
+ display: flex;
22
+ flex-direction: column;
23
+ gap: 1.25rem;
24
+ padding: 1.15rem 1.35rem 1.35rem;
25
+ }
26
+
27
+ .vertebr-font-library-note {
28
+ margin: 0;
29
+ color: var(--vb-muted);
30
+ font-size: 0.875rem;
31
+ }
32
+
33
+ .vertebr-font-library-grid,
34
+ .vertebr-font-picker-grid,
35
+ .vertebr-google-fonts-grid {
36
+ display: grid;
37
+ gap: 1rem;
38
+ align-content: start;
39
+ }
40
+
41
+ .vertebr-font-library-grid {
42
+ grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
43
+ }
44
+
45
+ .vertebr-font-library-card,
46
+ .vertebr-google-fonts-card {
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: 0.75rem;
50
+ padding: 1rem;
51
+ border: 1px solid var(--vb-line);
52
+ border-radius: 0.75rem;
53
+ background: var(--vb-surface);
54
+ min-width: 0;
55
+ }
56
+
57
+ .vertebr-font-library-preview-btn,
58
+ .vertebr-google-fonts-preview-btn {
59
+ display: flex;
60
+ flex-direction: column;
61
+ gap: 0.45rem;
62
+ width: 100%;
63
+ padding: 0;
64
+ border: 0;
65
+ background: transparent;
66
+ color: inherit;
67
+ text-align: left;
68
+ cursor: pointer;
69
+ }
70
+
71
+ .vertebr-font-library-preview-btn:hover .vertebr-font-library-preview,
72
+ .vertebr-google-fonts-preview-btn:hover .vertebr-google-fonts-card-copy {
73
+ border-color: var(--vb-accent);
74
+ }
75
+
76
+ .vertebr-font-library-preview {
77
+ display: flex;
78
+ flex-direction: column;
79
+ gap: 0.35rem;
80
+ min-height: 5.5rem;
81
+ padding: 0.75rem;
82
+ border: 1px solid var(--vb-line);
83
+ border-radius: 0.5rem;
84
+ background: var(--vb-bg);
85
+ transition: border-color 0.15s ease;
86
+ }
87
+
88
+ .vertebr-font-library-preview-hint {
89
+ color: var(--vb-muted);
90
+ font-size: 0.72rem;
91
+ }
92
+
93
+ .vertebr-font-library-ag {
94
+ font-size: 2rem;
95
+ line-height: 1;
96
+ }
97
+
98
+ .vertebr-font-library-preview p,
99
+ .vertebr-font-picker-preview p,
100
+ .vertebr-font-preview-body {
101
+ margin: 0;
102
+ font-size: 0.95rem;
103
+ line-height: 1.45;
104
+ }
105
+
106
+ .vertebr-font-library-meta {
107
+ display: flex;
108
+ flex-direction: column;
109
+ gap: 0.2rem;
110
+ min-width: 0;
111
+ }
112
+
113
+ .vertebr-font-library-meta strong {
114
+ overflow: hidden;
115
+ text-overflow: ellipsis;
116
+ white-space: nowrap;
117
+ }
118
+
119
+ .vertebr-font-library-meta span,
120
+ .vertebr-font-library-meta code {
121
+ color: var(--vb-muted);
122
+ font-size: 0.8rem;
123
+ }
124
+
125
+ .vertebr-font-library-meta code {
126
+ overflow: hidden;
127
+ text-overflow: ellipsis;
128
+ white-space: nowrap;
129
+ }
130
+
131
+ .vertebr-google-fonts {
132
+ display: flex;
133
+ flex-direction: column;
134
+ gap: 1rem;
135
+ padding: 1rem;
136
+ border: 1px solid var(--vb-line);
137
+ border-radius: 0.75rem;
138
+ background: color-mix(in srgb, var(--vb-surface) 88%, var(--vb-bg));
139
+ }
140
+
141
+ .vertebr-google-fonts-head {
142
+ display: flex;
143
+ flex-wrap: wrap;
144
+ align-items: end;
145
+ justify-content: space-between;
146
+ gap: 1rem;
147
+ }
148
+
149
+ .vertebr-google-fonts-head h3,
150
+ .vertebr-font-picker-modal-head h3,
151
+ .vertebr-font-preview-modal-head h3 {
152
+ margin: 0;
153
+ }
154
+
155
+ .vertebr-google-fonts-head p,
156
+ .vertebr-font-picker-modal-head p,
157
+ .vertebr-font-preview-modal-head p {
158
+ margin: 0.25rem 0 0;
159
+ color: var(--vb-muted);
160
+ font-size: 0.875rem;
161
+ }
162
+
163
+ .vertebr-google-fonts-search {
164
+ min-width: 14rem;
165
+ padding: 0.55rem 0.75rem;
166
+ border: 1px solid var(--vb-line);
167
+ border-radius: 0.5rem;
168
+ background: var(--vb-bg);
169
+ color: var(--vb-ink);
170
+ }
171
+
172
+ .vertebr-google-fonts-grid-scroll {
173
+ max-height: min(18rem, 42vh);
174
+ overflow: auto;
175
+ padding-right: 0.15rem;
176
+ }
177
+
178
+ .vertebr-google-fonts-grid {
179
+ grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
180
+ }
181
+
182
+ .vertebr-google-fonts-card-copy {
183
+ display: flex;
184
+ flex-direction: column;
185
+ gap: 0.15rem;
186
+ padding: 0.65rem;
187
+ border: 1px solid var(--vb-line);
188
+ border-radius: 0.5rem;
189
+ background: var(--vb-bg);
190
+ transition: border-color 0.15s ease;
191
+ }
192
+
193
+ .vertebr-google-fonts-card-copy span {
194
+ color: var(--vb-muted);
195
+ font-size: 0.8rem;
196
+ }
197
+
198
+ .vertebr-font-picker {
199
+ display: flex;
200
+ flex-direction: column;
201
+ gap: 1rem;
202
+ }
203
+
204
+ .vertebr-font-picker-current {
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: space-between;
208
+ gap: 1rem;
209
+ padding: 0.85rem 1rem;
210
+ border: 1px solid var(--vb-line);
211
+ border-radius: 0.65rem;
212
+ background: var(--vb-surface);
213
+ }
214
+
215
+ .vertebr-font-picker-current strong {
216
+ display: block;
217
+ }
218
+
219
+ .vertebr-font-picker-current span {
220
+ color: var(--vb-muted);
221
+ font-size: 0.875rem;
222
+ }
223
+
224
+ .vertebr-font-picker-preview {
225
+ padding: 1rem;
226
+ border: 1px dashed var(--vb-line);
227
+ border-radius: 0.65rem;
228
+ }
229
+
230
+ .vertebr-font-picker-modal-backdrop,
231
+ .vertebr-font-preview-modal-backdrop {
232
+ position: fixed;
233
+ inset: 0;
234
+ z-index: 40;
235
+ display: grid;
236
+ place-items: center;
237
+ padding: 1.5rem;
238
+ background: rgb(0 0 0 / 45%);
239
+ }
240
+
241
+ .vertebr-font-picker-modal,
242
+ .vertebr-font-preview-modal {
243
+ width: min(52rem, 100%);
244
+ max-height: min(88vh, 44rem);
245
+ display: flex;
246
+ flex-direction: column;
247
+ gap: 1rem;
248
+ padding: 1.25rem;
249
+ border: 1px solid var(--vb-line);
250
+ border-radius: 0.85rem;
251
+ background: var(--vb-bg);
252
+ box-shadow: 0 24px 64px rgb(0 0 0 / 18%);
253
+ overflow: hidden;
254
+ }
255
+
256
+ .vertebr-font-preview-modal {
257
+ width: min(40rem, 100%);
258
+ }
259
+
260
+ .vertebr-font-picker-modal-head,
261
+ .vertebr-font-preview-modal-head {
262
+ display: flex;
263
+ align-items: start;
264
+ justify-content: space-between;
265
+ gap: 1rem;
266
+ flex-shrink: 0;
267
+ }
268
+
269
+ .vertebr-font-picker-modal-body {
270
+ display: grid;
271
+ grid-template-columns: minmax(0, 1.2fr) minmax(14rem, 0.9fr);
272
+ gap: 1rem;
273
+ min-height: 0;
274
+ flex: 1 1 auto;
275
+ }
276
+
277
+ .vertebr-font-picker-grid-scroll {
278
+ min-height: 0;
279
+ max-height: min(52vh, 28rem);
280
+ overflow: auto;
281
+ padding-right: 0.2rem;
282
+ }
283
+
284
+ .vertebr-font-picker-grid {
285
+ grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
286
+ }
287
+
288
+ .vertebr-font-picker-detail {
289
+ min-height: 0;
290
+ max-height: min(52vh, 28rem);
291
+ overflow: auto;
292
+ display: flex;
293
+ flex-direction: column;
294
+ gap: 0.75rem;
295
+ padding: 1rem;
296
+ border: 1px solid var(--vb-line);
297
+ border-radius: 0.65rem;
298
+ background: var(--vb-surface);
299
+ }
300
+
301
+ .vertebr-font-picker-detail-label {
302
+ margin: 0;
303
+ color: var(--vb-muted);
304
+ font-size: 0.72rem;
305
+ letter-spacing: 0.14em;
306
+ text-transform: uppercase;
307
+ }
308
+
309
+ .vertebr-font-picker-modal-actions,
310
+ .vertebr-font-preview-modal-actions {
311
+ display: flex;
312
+ justify-content: flex-end;
313
+ gap: 0.65rem;
314
+ flex-shrink: 0;
315
+ padding-top: 0.15rem;
316
+ border-top: 1px solid var(--vb-line);
317
+ }
318
+
319
+ .vertebr-font-picker-option {
320
+ display: flex;
321
+ flex-direction: column;
322
+ gap: 0.2rem;
323
+ min-height: 6.5rem;
324
+ padding: 0.85rem;
325
+ border: 1px solid var(--vb-line);
326
+ border-radius: 0.65rem;
327
+ background: var(--vb-bg);
328
+ color: var(--vb-ink);
329
+ text-align: left;
330
+ cursor: pointer;
331
+ }
332
+
333
+ .vertebr-font-picker-option[data-active] {
334
+ border-color: var(--vb-accent);
335
+ box-shadow: inset 0 0 0 1px var(--vb-accent);
336
+ }
337
+
338
+ .vertebr-font-picker-option span,
339
+ .vertebr-font-picker-option em {
340
+ color: var(--vb-muted);
341
+ font-size: 0.8rem;
342
+ font-style: normal;
343
+ }
344
+
345
+ .vertebr-font-preview-modal-body {
346
+ overflow: auto;
347
+ min-height: 0;
348
+ }
349
+
350
+ .vertebr-font-preview-sample {
351
+ display: flex;
352
+ flex-direction: column;
353
+ gap: 0.65rem;
354
+ }
355
+
356
+ .vertebr-font-preview-sample[data-compact="true"] {
357
+ gap: 0.4rem;
358
+ }
359
+
360
+ .vertebr-font-preview-eyebrow {
361
+ font-size: 0.72rem;
362
+ letter-spacing: 0.18em;
363
+ text-transform: uppercase;
364
+ }
365
+
366
+ .vertebr-font-preview-heading {
367
+ font-size: clamp(1.5rem, 3vw, 2rem);
368
+ line-height: 1.15;
369
+ }
370
+
371
+ .vertebr-font-preview-alphabet {
372
+ font-size: 0.82rem;
373
+ line-height: 1.55;
374
+ color: var(--vb-muted);
375
+ }
376
+
377
+ .vertebr-font-preview-weights {
378
+ display: flex;
379
+ flex-wrap: wrap;
380
+ gap: 0.75rem;
381
+ font-size: 0.85rem;
382
+ }
383
+
384
+ .vertebr-error-inline {
385
+ color: var(--vb-danger, #b42318);
386
+ font-size: 0.875rem;
387
+ }
388
+
389
+ @media (max-width: 760px) {
390
+ .vertebr-font-picker-modal-body {
391
+ grid-template-columns: 1fr;
392
+ }
393
+
394
+ .vertebr-font-picker-detail {
395
+ max-height: none;
396
+ }
397
+
398
+ .vertebr-font-picker-grid-scroll {
399
+ max-height: min(34vh, 18rem);
400
+ }
401
+ }
@@ -1,7 +1,7 @@
1
1
  /* ── Form ────────────────────────────────────────────── */
2
2
 
3
3
  .vertebr-form {
4
- flex: 1 1 auto;
4
+ flex: 1 1 0%;
5
5
  min-height: 0;
6
6
  display: flex;
7
7
  flex-direction: column;
@@ -101,6 +101,62 @@
101
101
  height: 1.85rem;
102
102
  }
103
103
 
104
+ .vertebr-form-fields[data-layout="settings"] {
105
+ display: block;
106
+ padding: 1.05rem 1.1rem 1.15rem;
107
+ }
108
+
109
+ .vertebr-settings-list {
110
+ margin: 0;
111
+ padding: 0;
112
+ list-style: none;
113
+ display: flex;
114
+ flex-direction: column;
115
+ border: 1px solid var(--vb-border);
116
+ border-radius: var(--vb-radius-sm);
117
+ background: var(--vb-bg);
118
+ overflow: hidden;
119
+ }
120
+
121
+ .vertebr-settings-list-row {
122
+ display: flex;
123
+ align-items: center;
124
+ justify-content: space-between;
125
+ gap: 0.75rem;
126
+ padding: 0.65rem 0.75rem;
127
+ border-bottom: 1px solid var(--vb-border);
128
+ }
129
+
130
+ .vertebr-settings-list-row:last-child {
131
+ border-bottom: 0;
132
+ }
133
+
134
+ .vertebr-settings-list-row[data-on="false"] {
135
+ opacity: 0.55;
136
+ }
137
+
138
+ .vertebr-settings-list-copy {
139
+ display: flex;
140
+ flex-direction: column;
141
+ gap: 0.15rem;
142
+ min-width: 0;
143
+ flex: 1 1 auto;
144
+ }
145
+
146
+ .vertebr-settings-list-copy label {
147
+ font-size: 0.86rem;
148
+ font-weight: 500;
149
+ color: var(--vb-text);
150
+ cursor: pointer;
151
+ }
152
+
153
+ .vertebr-settings-list-desc {
154
+ margin: 0;
155
+ font-size: 0.78rem;
156
+ line-height: 1.4;
157
+ color: var(--vb-text-muted);
158
+ }
159
+
104
160
  .vertebr-form-fields[data-layout="chips"] .vertebr-field label {
105
161
  font-family: var(--vb-mono);
106
162
  font-size: 0.7rem;
@@ -705,6 +761,21 @@
705
761
  grid-column: 1 / -1;
706
762
  }
707
763
 
764
+ .vertebr-switch-row-copy {
765
+ display: flex;
766
+ flex-direction: column;
767
+ gap: 0.15rem;
768
+ min-width: 0;
769
+ flex: 1 1 auto;
770
+ }
771
+
772
+ .vertebr-switch-row-desc {
773
+ margin: 0;
774
+ font-size: 0.78rem;
775
+ line-height: 1.4;
776
+ color: var(--vb-text-muted);
777
+ }
778
+
708
779
  .vertebr-switch-row label {
709
780
  font-size: 0.88rem;
710
781
  font-weight: 500;
@@ -747,16 +818,31 @@
747
818
 
748
819
  .vertebr-actions {
749
820
  flex: 0 0 auto;
750
- z-index: 3;
821
+ position: relative;
822
+ z-index: 5;
751
823
  display: flex;
752
824
  align-items: center;
753
825
  gap: 0.75rem;
754
826
  padding: 0.85rem 1.35rem;
827
+ /* Home indicator / browser chrome */
828
+ padding-bottom: calc(0.85rem + env(safe-area-inset-bottom, 0px));
755
829
  border-top: 1px solid var(--vb-border);
756
- background: var(--vb-bg-elevated);
830
+ background: linear-gradient(
831
+ 180deg,
832
+ var(--vb-actions-from) 0%,
833
+ var(--vb-actions-to) 100%
834
+ );
835
+ backdrop-filter: blur(10px);
757
836
  box-shadow: 0 -10px 24px -18px color-mix(in srgb, var(--vb-text) 40%, transparent);
758
837
  }
759
838
 
839
+ /* iPadOS floating dock overlays the page and is NOT in safe-area-inset. */
840
+ @media (pointer: coarse) {
841
+ .vertebr-actions {
842
+ padding-bottom: calc(0.85rem + env(safe-area-inset-bottom, 0px) + 4.75rem);
843
+ }
844
+ }
845
+
760
846
  .vertebr-actions-spacer {
761
847
  flex: 1;
762
848
  }
@@ -1,4 +1,4 @@
1
- /* Vertebr React styles — public entry. Partials live in ./styles/ */
1
+ /* Vertebr React styles ? public entry. Partials live in ./styles/ */
2
2
  @import "../themes/index.css";
3
3
  @import "./base.css";
4
4
  @import "./sidebar.css";
@@ -18,4 +18,6 @@
18
18
  @import "./form.css";
19
19
  @import "./buttons.css";
20
20
  @import "./gallery.css";
21
+ @import "./font-library.css";
22
+ @import "./page-preview.css";
21
23
  @import "./states.css";
@@ -27,7 +27,7 @@
27
27
  }
28
28
 
29
29
  .vertebr-content {
30
- flex: 1 1 auto;
30
+ flex: 1 1 0%;
31
31
  min-width: 0;
32
32
  min-height: 0;
33
33
  display: flex;