Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Privacy policy β€” Clay Slip

_Last updated: 2026-05-13_
_Last updated: 2026-05-19_

Clay Slip is a developer tool. It runs entirely on your device, in your browser. **It does not collect, transmit, sell, or share any personal data.**

Expand All @@ -22,10 +22,10 @@ This document is the canonical privacy disclosure for the extension. It's distri

Clay Slip uses the standard WebExtension storage APIs (`chrome.storage` on Chromium, `browser.storage` on Firefox β€” same shape, same data, same guarantees). Stored data never leaves the user's device or browser-vendor account.

| Storage area | Contents | Why |
| --------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `storage.sync` | UI preferences (theme, panel position/size, site host mappings, highlight mode + intensity, shortcut toggle) | Carries your settings across browsers when you're signed in to Chrome / Firefox Sync. |
| `storage.local` | Sticky-note annotations pinned to component URIs; "recently viewed components" history (capped, configurable) | Keeps notes and history available offline; not synced because they may include page-specific context. |
| Storage area | Contents | Why |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `storage.sync` | UI preferences (theme, panel position/size, site host mappings, window globals list, highlight mode + intensity, shortcut toggle) | Carries your settings across browsers when you're signed in to Chrome / Firefox Sync. |
| `storage.local` | Sticky-note annotations pinned to component URIs; "recently viewed components" history (capped, configurable) | Keeps notes and history available offline; not synced because they may include page-specific context. |

You can clear everything from the extension's **Options** page (Reset preferences, Clear history) or via your browser's _Manage extensions_ β†’ _Site access / storage_ controls (Chromium) or `about:addons` β†’ Clay Slip β†’ _Remove_ (Firefox).

Expand All @@ -38,6 +38,7 @@ To do its job, the content script reads:
- The `data-uri` and `data-editable` attributes that Clay sites set on rendered components.
- Standard `<head>` metadata (`<title>`, `<meta>` tags, `<link rel="canonical">`, JSON-LD) for the SEO tab.
- The text/HTML of components you explicitly select for the JSON tab and Diff tab.
- **Only the top-level `window.*` globals you explicitly list on the Options page (Window globals)**, and only when you open the **Globals** tab or click **Refresh**. The extension injects a tiny one-time bridge script into the page's main world, which reads `window[key]` for each configured key, `JSON.stringify`s it, and posts the result back to the panel. The script never reads any global you didn't configure, and never reads anything until you ask the Globals tab for data.

This data is **only ever displayed inside the panel on your machine.** It is never sent anywhere except, when you explicitly ask, to the same Clay host the page came from (see "Outbound network requests" below).

Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ The same source builds for both browser families:
- **Shareable selection links** β€” copy a `?clay-slip-select=…` URL that auto-opens the panel and selects the same component on someone else's machine
- **Component screenshot to clipboard** β€” one-click PNG of any selected component, panel auto-hides during capture
- **SEO tab** β€” title / meta / og / twitter / JSON-LD with a Twitter + Facebook card preview and lints (length, missing image, duplicate `<h1>`, etc.)
- **Window globals tab** β€” surface any top-level `window.*` value your page sets at boot (e.g. `nymGtmPage`, `dataLayer`, custom analytics payloads) as syntax-highlighted JSON. Configurable list per install; arrays and objects render identically; per-row and tab-level refresh, no ambient polling
- **Recently viewed components** persisted across sessions, with one-click jump back
- **Resizable + dockable panel** β€” drag the inner edges (or the inner-corner grabber) to resize width _and_ height; choose any of four corners or a full-height left/right side dock
- **Refined highlight modes** β€” _Off_, _Selection_ (default; pristine page, hover and click highlight in blue, hold <kbd>βŒƒ</kbd> Control to flash the rainbow over every component), _Editable only_ (always-on subtle corner accents on `[data-editable]`), or _All components_ (always-on rainbow over every component, like the original Clay devtools). Hover and selected always paint in a single blue accent β€” outline + inset tint β€” so the "you clicked it" feedback reads consistently across every mode, on top of either the rainbow or the corner-accent ambient layer. Top-left labelled badge follows your hover and selection. Switch modes from the panel header dropdown or with the <kbd>h</kbd> shortcut.
Expand Down Expand Up @@ -140,6 +141,7 @@ Stored preferences/notes can also be cleared from the Options page (**Clear rece
| Show shortcut overlay | Press <kbd>?</kbd> |
| Toggle FAB ↔ panel | Press <kbd>[</kbd> or click the collapse button / the FAB |
| Switch tabs | Press <kbd>i</kbd> (Inspect) or <kbd>t</kbd> (Tree) |
| Read a window global | **Globals** tab β†’ expand the row for the configured global; **↻** re-reads from the current page |
| Open settings | Click the gear icon in the panel header |

## Screenshots
Expand Down Expand Up @@ -170,6 +172,24 @@ Example for a Vox-Media-style multi-brand setup:

Hostnames are matched **exactly** (case-insensitive) β€” no prefix stripping or wildcards β€” so the mapping does what you wrote and nothing more. There&rsquo;s no separate global env config; if a host isn&rsquo;t in any mapping, the extension falls back to whatever host the Clay component URI itself encodes, which is also the page&rsquo;s host.

### Window globals

The **Window globals** section on the options page lists the top-level `window.*` keys you want to inspect on every Clay page. Each configured global gets its own collapsible card in the **Globals** panel tab.

- Enter the name as either `nymGtmPage` or `window.nymGtmPage` β€” the extension strips the prefix and normalizes the rest. Whitespace around the value is trimmed.
- Both **objects** and **arrays** render identically β€” the panel just shows their `JSON.stringify` output with syntax highlighting.
- Reads happen on initial tab open and on explicit **Refresh** clicks (per-row or tab-level **Refresh all**). There is no background polling β€” the page only does work when you ask it to, so this tab has no measurable runtime cost.

Limitations and edge cases (surfaced inline in the tab):

- **Top-level only.** Nested paths (`foo.bar.baz`) and array indices (`dataLayer[0]`) aren&rsquo;t supported yet. Add the top-level global; expand the row to drill into the structure.
- **`(not defined on this page)`** β€” the global isn&rsquo;t set on the current page. Most often a navigation timing issue: try Refresh after the page has finished loading.
- **`(value is not JSON-serializable)`** β€” the global is a function or `Symbol`. `JSON.stringify` can&rsquo;t round-trip those; nothing the extension can do beyond surfacing the fact.
- **`(could not serialize: …)`** β€” the value contains a circular reference. The underlying JS error is embedded in the message.
- **`(could not read from this page)`** β€” a strict Content Security Policy or Trusted Types policy blocked the page-bridge injection. Refresh the page and try again; if it persists, the host page&rsquo;s CSP is the cause.

Internally this works by injecting a tiny one-time script into the page&rsquo;s main world that listens for postMessages and replies with the JSON-stringified value. The script never reads anything you didn&rsquo;t configure on the options page. Full design write-up: [`docs/specs/2026-05-19-window-globals-tab.md`](docs/specs/2026-05-19-window-globals-tab.md).

## Build from source

For contributors and anyone who wants to run the extension from a local checkout instead of a release zip:
Expand Down
Loading