@sevenfold/setto-client 0.3.4 → 0.5.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.
- package/README.md +61 -36
- package/dist/SettoRepeater.d.ts +2 -1
- package/dist/admin/App.d.ts +4 -5
- package/dist/edit-mode/constants.d.ts +4 -2
- package/dist/edit-mode/document-layout.d.ts +4 -2
- package/dist/edit-mode/mount.d.ts +2 -2
- package/dist/edit-mode/setto-mark.d.ts +16 -0
- package/dist/guest-edit.d.ts +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/lib/theme-store.d.ts +2 -0
- package/dist/lib/urls.d.ts +13 -3
- package/dist/lib/use-site-access.d.ts +16 -0
- package/dist/provider.d.ts +10 -5
- package/dist/setto-client.js +426 -249
- package/dist/setto-client.js.map +1 -1
- package/dist/theme-target-utils.d.ts +2 -2
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -8,29 +8,34 @@ Editors authenticate via Supabase, edit text inline on the live page, pick secti
|
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
Sevenfold sites pin a git tag, not an npm version, so changes ship without an npm round-trip:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
"@setto/client": "github:nitech/setto-client#v0.5.0"
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
Bun clones the repo on `bun install`, runs the package's `prepare` script to build `dist/`, and links it as `@setto/client`. Vercel does the same automatically when it installs build deps.
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
The package is also still published to npm (`@sevenfold/setto-client`) for external consumers:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
bun add @setto/client@npm:@sevenfold/setto-client
|
|
19
23
|
```
|
|
20
24
|
|
|
21
25
|
Peer deps: `react`, `react-dom`, `react-i18next`, `i18next`.
|
|
22
26
|
|
|
23
|
-
For local monorepo development
|
|
27
|
+
For local monorepo development the consumer's `vite.config.ts` aliases `@setto/client` to setto-client source — see [Local development](#local-development-sevenfold-monorepo).
|
|
24
28
|
|
|
25
|
-
###
|
|
29
|
+
### Releasing a new version
|
|
26
30
|
|
|
27
|
-
1. Bump `version` in `package.json`
|
|
28
|
-
2. Commit and
|
|
29
|
-
3.
|
|
31
|
+
1. Bump `version` in `package.json` following semver (patch / minor / major).
|
|
32
|
+
2. Commit and tag: `git tag v0.5.1 && git push origin main --follow-tags`.
|
|
33
|
+
3. In each consumer (`carryon.no`, `setto-site`):
|
|
34
|
+
- Update the tag in `package.json` (e.g. `#v0.5.0` → `#v0.5.1`).
|
|
35
|
+
- Run `bun install` to refresh the lockfile.
|
|
36
|
+
- Push — Vercel pulls the new tag on the next deploy.
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Or trigger manually via **Actions → Publish to npm → Run workflow**.
|
|
38
|
+
GitHub Actions still publishes to npm automatically when `package.json` lands on `main` (requires `NPM_TOKEN` secret), but Sevenfold consumers no longer wait for it.
|
|
34
39
|
|
|
35
40
|
---
|
|
36
41
|
|
|
@@ -67,7 +72,9 @@ createRoot(document.getElementById('root')!).render(
|
|
|
67
72
|
);
|
|
68
73
|
```
|
|
69
74
|
|
|
70
|
-
### 2. Mount the
|
|
75
|
+
### 2. Mount the Setto route
|
|
76
|
+
|
|
77
|
+
Editors sign in once at `sitenavn.no/setto`. After that, every visit to the public site auto-enters edit mode for as long as the Supabase session persists.
|
|
71
78
|
|
|
72
79
|
```tsx
|
|
73
80
|
// App.tsx
|
|
@@ -75,7 +82,7 @@ import { SettoAdminApp } from '@setto/client';
|
|
|
75
82
|
|
|
76
83
|
<Routes>
|
|
77
84
|
<Route path="/" element={<Home />} />
|
|
78
|
-
<Route path="/
|
|
85
|
+
<Route path="/setto/*" element={<SettoAdminApp />} />
|
|
79
86
|
</Routes>
|
|
80
87
|
```
|
|
81
88
|
|
|
@@ -124,24 +131,32 @@ function ValuesSection() {
|
|
|
124
131
|
|
|
125
132
|
## Edit mode
|
|
126
133
|
|
|
127
|
-
Edit mode activates
|
|
134
|
+
Edit mode activates whenever **all** of these are true:
|
|
128
135
|
|
|
129
|
-
1.
|
|
130
|
-
2.
|
|
136
|
+
1. The user has an authenticated Supabase session.
|
|
137
|
+
2. The user has access to `config.siteId` (a row in the `sites` table that they can read).
|
|
138
|
+
3. The current path is not `/setto` (the dashboard is rendered without inline editing).
|
|
131
139
|
|
|
132
|
-
|
|
140
|
+
Sign-in at `/setto` persists via Supabase, so subsequent visits drop straight into edit mode — no URL flag, no extra step.
|
|
133
141
|
|
|
134
142
|
### What editors see
|
|
135
143
|
|
|
144
|
+
A small round Setto button floats in the bottom-right corner. While there are no unpublished changes it stays as a circle showing only the Setto mark. As soon as you edit something it grows into a pill containing **Publiser** and a **⋯** menu with:
|
|
145
|
+
|
|
146
|
+
| Item | Effect |
|
|
147
|
+
|------|--------|
|
|
148
|
+
| **Avbryt** | Discards every unsaved draft (text, section colours, image uploads) |
|
|
149
|
+
| **Logg ut** | Signs out via Supabase and exits edit mode |
|
|
150
|
+
| **Historikk** | Opens the `/setto` dashboard with deployment history |
|
|
151
|
+
|
|
136
152
|
| Action | How |
|
|
137
153
|
|--------|-----|
|
|
138
154
|
| Edit text | Click any `<T>` element — it becomes `contentEditable` |
|
|
139
155
|
| Edit section colours | Click a section or block background (not text) |
|
|
140
156
|
| Follow a link | Ctrl/Cmd + click (desktop) · **Naviger ↗** chip when focused (touch) |
|
|
141
|
-
| Publish |
|
|
142
|
-
| Exit | Top toolbar → **Avslutt** (removes `?setto=edit`) |
|
|
157
|
+
| Publish | FAB → **Publiser** (visible once you have drafts) |
|
|
143
158
|
|
|
144
|
-
|
|
159
|
+
When you click a section or block, a compact colour toolbar appears above it. Click again or press Escape to dismiss.
|
|
145
160
|
|
|
146
161
|
---
|
|
147
162
|
|
|
@@ -272,31 +287,41 @@ Click a block's background to edit **that block's** colours. Click the section p
|
|
|
272
287
|
|
|
273
288
|
## Server setup (setto-server)
|
|
274
289
|
|
|
275
|
-
|
|
290
|
+
Site configuration is split in two:
|
|
291
|
+
|
|
292
|
+
**1. Supabase `sites` row — control plane (where + routing).** Set once when the site is registered (platform admin → **Ny side**):
|
|
276
293
|
|
|
277
294
|
| Column | Example |
|
|
278
295
|
|--------|---------|
|
|
279
|
-
| `id` | `carryon-no` |
|
|
296
|
+
| `id` | `carryon-no` (must match `siteId` in `SettoProvider`) |
|
|
280
297
|
| `repo_owner` / `repo_name` / `branch` | GitHub target |
|
|
281
|
-
| `
|
|
298
|
+
| `vercel_project_id` | `prj_…` (used to route Vercel webhooks) |
|
|
282
299
|
|
|
283
|
-
|
|
300
|
+
**2. `setto.config.json` in the site repo root — content shape.** setto-server reads this from GitHub (cached, with a DB fallback):
|
|
284
301
|
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
302
|
+
```json
|
|
303
|
+
{
|
|
304
|
+
"displayName": "Carry On",
|
|
305
|
+
"contentPaths": [
|
|
306
|
+
"src/i18n/locales/no.json",
|
|
307
|
+
"src/i18n/locales/en.json",
|
|
308
|
+
"src/theme/sections.json",
|
|
309
|
+
"public/images/setto/"
|
|
310
|
+
],
|
|
311
|
+
"allowedOrigins": ["https://carryon.no", "http://localhost:3000"]
|
|
312
|
+
}
|
|
289
313
|
```
|
|
290
314
|
|
|
291
|
-
|
|
315
|
+
- `contentPaths` is the publish whitelist — only these paths can be committed. Add new content files here before publishing them. `setto.config.json` itself is intentionally not in the list, so editors can never widen their own access.
|
|
316
|
+
- `allowedOrigins` is the CORS allow-list; the first entry is also used as the editor-invite activation domain.
|
|
292
317
|
|
|
293
|
-
|
|
318
|
+
Keeping this in the repo means content shape lives with the code that defines it, and no DB change is needed when you add a content file — just commit the config. The legacy `content_paths` / `allowed_origins` / `display_name` DB columns remain as a fallback for sites without the file.
|
|
294
319
|
|
|
295
320
|
---
|
|
296
321
|
|
|
297
322
|
## Publish flow
|
|
298
323
|
|
|
299
|
-
1. Editor clicks **Publiser** in the
|
|
324
|
+
1. Editor clicks **Publiser** in the floating FAB.
|
|
300
325
|
2. Client serialises changed locale bundles + `sections.json` (if theme drafts exist).
|
|
301
326
|
3. `POST /sites/:siteId/publish` with `{ files: [{ path, content }] }`.
|
|
302
327
|
4. setto-server validates paths against `content_paths`, commits to GitHub.
|
|
@@ -308,9 +333,9 @@ Drafts are cleared after a successful publish.
|
|
|
308
333
|
|
|
309
334
|
## Admin app (`SettoAdminApp`)
|
|
310
335
|
|
|
311
|
-
Route: `/
|
|
336
|
+
Route: `/setto/*`
|
|
312
337
|
|
|
313
|
-
Provides Supabase email/password login (invite-only — no self-service sign-up), password reset, and a dashboard
|
|
338
|
+
Provides Supabase email/password login (invite-only — no self-service sign-up), password reset, and a dashboard. After sign-in the dashboard redirects to the site home, where edit mode auto-activates. Invite links from Supabase land on `/setto` to set a password. Does not render the inline editor itself.
|
|
314
339
|
|
|
315
340
|
---
|
|
316
341
|
|
|
@@ -353,7 +378,7 @@ Produces `dist/setto-client.js` and `.d.ts` via Vite library mode. Only needed b
|
|
|
353
378
|
| `SettoSection` | Section wrapper + edit selection |
|
|
354
379
|
| `SettoBlock` | Nested card/panel with its own colour toolbar |
|
|
355
380
|
| `useSectionTheme` | Read section colour tokens |
|
|
356
|
-
| `SettoAdminApp` | `/
|
|
381
|
+
| `SettoAdminApp` | `/setto` login + dashboard |
|
|
357
382
|
| `AuthGate` | Standalone login wrapper |
|
|
358
383
|
| `BrandColor`, `SectionSchema`, `SettoConfig` | Types for host config |
|
|
359
384
|
|
package/dist/SettoRepeater.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface SettoRepeaterProps {
|
|
|
10
10
|
className?: string;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Renders a dynamic list from i18n. In edit mode, editors can add
|
|
13
|
+
* Renders a dynamic list from i18n. In edit mode, editors can add items (button
|
|
14
|
+
* at the end of the list) and remove items (round × revealed on hover).
|
|
14
15
|
*/
|
|
15
16
|
export declare function SettoRepeater({ itemsKey, defaultItem, itemLabel, children, className, }: SettoRepeaterProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/admin/App.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Drop-in admin SPA. Mount under a route like `<Route path="/
|
|
2
|
+
* Drop-in admin SPA. Mount under a route like `<Route path="/setto/*" .../>`.
|
|
3
3
|
*
|
|
4
4
|
* Behaviour after login:
|
|
5
|
-
* - Redirects to
|
|
5
|
+
* - Redirects to the site home `/`. Edit mode activates automatically there
|
|
6
|
+
* via `SettoProvider` when the user has access to `config.siteId`.
|
|
6
7
|
* - Shows the dashboard only when the user lacks access to this site, or on
|
|
7
|
-
* `/
|
|
8
|
-
*
|
|
9
|
-
* Editing happens on the public site at `/?setto=edit`.
|
|
8
|
+
* `/setto?deployment=…` for publish progress / history.
|
|
10
9
|
*/
|
|
11
10
|
export declare function SettoAdminApp(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
export declare const
|
|
1
|
+
/** Diameter of the collapsed FAB and height of the expanded pill (px). */
|
|
2
|
+
export declare const FAB_SIZE = 52;
|
|
3
|
+
/** Distance from the viewport edges to the FAB (px). */
|
|
4
|
+
export declare const FAB_INSET = 16;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Applies the document-level CSS for inline edit mode. The fixed top toolbar
|
|
3
|
+
* has been replaced with a floating FAB anchored bottom-right, so the host
|
|
4
|
+
* page no longer needs vertical padding — only edit-affordance hover styles
|
|
5
|
+
* and the portal layers above the page.
|
|
4
6
|
*/
|
|
5
7
|
export declare function useSettoDocumentLayout(active: boolean): void;
|
|
@@ -5,8 +5,8 @@ interface EditModeShellProps {
|
|
|
5
5
|
themeStore: ThemeStore | null;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Edit mode: full-width page with a
|
|
9
|
-
* inline via contentEditable on `<T>` — no sidebar.
|
|
8
|
+
* Edit mode: full-width page with a floating Setto FAB anchored bottom-right.
|
|
9
|
+
* Text is edited inline via contentEditable on `<T>` — no sidebar.
|
|
10
10
|
*/
|
|
11
11
|
export declare function EditModeShell({ children, themeStore }: EditModeShellProps): import("react/jsx-runtime").JSX.Element;
|
|
12
12
|
/** @deprecated Use EditModeShell */
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
interface SettoMarkProps {
|
|
3
|
+
size?: number;
|
|
4
|
+
/** Color of the "S" letter. Defaults to the Setto crema tone. */
|
|
5
|
+
letterColor?: string;
|
|
6
|
+
/** Color of the accent dot. Defaults to the Setto terracotta. */
|
|
7
|
+
dotColor?: string;
|
|
8
|
+
style?: CSSProperties;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Setto brand mark — the foreground of the setto-site favicon (italic "S" with
|
|
12
|
+
* a terracotta dot) on a transparent background. The FAB renders the dark
|
|
13
|
+
* Blekk background itself so the mark only carries the glyphs.
|
|
14
|
+
*/
|
|
15
|
+
export declare function SettoMark({ size, letterColor, dotColor, style, }: SettoMarkProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export {};
|
package/dist/guest-edit.d.ts
CHANGED
|
@@ -5,9 +5,9 @@ interface GuestEditContextValue {
|
|
|
5
5
|
stop: () => void;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Lets visitors inline-edit
|
|
9
|
-
*
|
|
10
|
-
* always takes precedence.
|
|
8
|
+
* Lets visitors inline-edit a marketing site (e.g. setto.no) without auth —
|
|
9
|
+
* text, section/block colours, icons and list items. Changes are session-only
|
|
10
|
+
* and never published. Real Setto edit mode always takes precedence.
|
|
11
11
|
*/
|
|
12
12
|
export declare function GuestEditProvider({ children }: {
|
|
13
13
|
children: ReactNode;
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export { SettoRepeater } from './SettoRepeater';
|
|
|
11
11
|
export type { SettoRepeaterProps } from './SettoRepeater';
|
|
12
12
|
export { useSectionTheme } from './use-section-theme';
|
|
13
13
|
export { SettoAdminApp } from './admin/App';
|
|
14
|
+
export { SETTO_BASE } from './lib/urls';
|
|
14
15
|
export { AuthGate } from './edit-mode/auth-gate';
|
|
15
16
|
export type { SettoConfig, BrandColor, DeploymentRow, SiteRow, ContentFile, PublishFile, PublishResult, } from './types';
|
|
16
17
|
export type { SectionSchema, SectionColorField } from './section-schema';
|
|
@@ -27,6 +27,8 @@ export declare class ThemeStore {
|
|
|
27
27
|
set(sectionId: string, field: string, value: string): void;
|
|
28
28
|
/** Replace baseline from GitHub without creating drafts. */
|
|
29
29
|
loadBaseline(next: SectionsTheme): void;
|
|
30
|
+
/** Resets every draft back to its original value. */
|
|
31
|
+
revertAll(): void;
|
|
30
32
|
commit(): void;
|
|
31
33
|
size(): number;
|
|
32
34
|
serialise(): SectionsTheme;
|
package/dist/lib/urls.d.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Base path where the Setto login + dashboard SPA is mounted on the host site.
|
|
3
|
+
* Editors reach the dashboard by visiting `sitenavn.no/setto`. The host app
|
|
4
|
+
* must mount `<SettoAdminApp>` at this path (e.g. `<Route path="/setto/*" …>`).
|
|
5
|
+
*/
|
|
6
|
+
export declare const SETTO_BASE = "/setto";
|
|
7
|
+
/**
|
|
8
|
+
* Site home URL used after sign-in. Edit mode itself is now driven by the
|
|
9
|
+
* Supabase session + site access — no URL flag required — so this just sends
|
|
10
|
+
* the editor to the public site root.
|
|
11
|
+
*/
|
|
12
|
+
export declare function siteHomeUrl(pathname?: string): string;
|
|
3
13
|
export declare function isAdminRoute(): boolean;
|
|
4
|
-
/**
|
|
14
|
+
/** Setto deployment progress panel (`/setto?deployment=…`). */
|
|
5
15
|
export declare function isAdminDeploymentView(): boolean;
|
|
6
16
|
export declare function adminRedirectUrl(): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Session, SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
import type { SiteRow } from '../types';
|
|
3
|
+
export interface SiteAccessState {
|
|
4
|
+
/** All sites the current user can access. `null` until loaded. */
|
|
5
|
+
sites: SiteRow[] | null;
|
|
6
|
+
/** The site matching `siteId`, or `null` if the user has no access. */
|
|
7
|
+
currentSite: SiteRow | null;
|
|
8
|
+
loading: boolean;
|
|
9
|
+
error: string | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Loads the sites table for the current Supabase session and resolves whether
|
|
13
|
+
* the user has access to `siteId`. Returns a stable shape across loading,
|
|
14
|
+
* success, and failure so callers can read `currentSite` directly.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useSiteAccess(supabase: SupabaseClient, session: Session | null, siteId: string): SiteAccessState;
|
package/dist/provider.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { type SettoApi } from './lib/api';
|
|
|
4
4
|
import { I18nStore } from './lib/i18n-store';
|
|
5
5
|
import { AssetStore } from './lib/asset-store';
|
|
6
6
|
import { ThemeStore } from './lib/theme-store';
|
|
7
|
-
import type { SettoConfig } from './types';
|
|
7
|
+
import type { SettoConfig, SiteRow } from './types';
|
|
8
8
|
interface SettoContextValue {
|
|
9
9
|
config: SettoConfig;
|
|
10
10
|
supabase: SupabaseClient;
|
|
@@ -12,8 +12,12 @@ interface SettoContextValue {
|
|
|
12
12
|
session: Session | null;
|
|
13
13
|
/** True while the initial auth state is being read from local storage. */
|
|
14
14
|
authLoading: boolean;
|
|
15
|
-
/** True when inline edit mode is active (
|
|
15
|
+
/** True when inline edit mode is active (session + site access). */
|
|
16
16
|
editMode: boolean;
|
|
17
|
+
/** Site row matching `config.siteId`, or `null` if the user has no access. */
|
|
18
|
+
currentSite: SiteRow | null;
|
|
19
|
+
/** All sites the user can access (loaded after sign-in). */
|
|
20
|
+
sites: SiteRow[] | null;
|
|
17
21
|
/**
|
|
18
22
|
* Lazily created when i18next is initialised. Components that need it
|
|
19
23
|
* should `if (!store) return null;` until then.
|
|
@@ -32,10 +36,11 @@ export interface SettoProviderProps {
|
|
|
32
36
|
*
|
|
33
37
|
* Edit mode is on when ALL of:
|
|
34
38
|
* 1. There is an authenticated Supabase session.
|
|
35
|
-
* 2. The
|
|
39
|
+
* 2. The user has access to `config.siteId` in the Setto sites table.
|
|
40
|
+
* 3. The current path is not the `/setto` admin SPA.
|
|
36
41
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
42
|
+
* Once an editor signs in via `/setto`, returning visits auto-enter edit mode
|
|
43
|
+
* for as long as the Supabase session persists.
|
|
39
44
|
*/
|
|
40
45
|
export declare function SettoProvider({ config, children }: SettoProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
41
46
|
export declare function useSetto(): SettoContextValue;
|