@stacklist-app/brandkit 1.2.2 → 1.2.3
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 +2 -0
- package/config.schema.json +2 -1
- package/dist/engine.js +59 -0
- package/dist/index.html +1 -0
- package/dist/styles.css +39 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,6 +43,8 @@ A brandkit guide isn't just a page for people — `build` (and the standalone `e
|
|
|
43
43
|
|
|
44
44
|
`build` also makes the data **discoverable from the deployed page**: it injects `<link rel="alternate" type="application/json" href="brand.json">` and embeds the brand inline as `<script type="application/json" id="brandkit-brand">`, so an agent that fetches the URL gets structured brand data with zero extra requests.
|
|
45
45
|
|
|
46
|
+
And for a person who wants to hand the guide to their own agent, the sidebar shows a **"Using an AI agent?"** callout with a one-click copy-paste prompt — it carries absolute URLs to `brand.json` / `tokens.json` / `brand.md` and tells the agent to read those instead of scraping the page. Hide it with `brand.agentCallout: false`.
|
|
47
|
+
|
|
46
48
|
A JSON Schema for `config.json` ships at [`config.schema.json`](config.schema.json) — point your editor's `$schema` at it for validation and autocomplete.
|
|
47
49
|
|
|
48
50
|
## Framework integrations
|
package/config.schema.json
CHANGED
|
@@ -51,7 +51,8 @@
|
|
|
51
51
|
"date": { "type": "string" },
|
|
52
52
|
"guideLabel": { "type": "string", "description": "Renames the 'Web Style Guide' label in the header and footer." },
|
|
53
53
|
"headerLogo": { "type": "string", "description": "Path to a logo image shown in the header instead of the text wordmark (use a light/reversed logo)." },
|
|
54
|
-
"sidebarLogo": { "type": "string", "description": "Path to a logo image shown at the top of the left menu instead of the brand name (use a dark logo)." }
|
|
54
|
+
"sidebarLogo": { "type": "string", "description": "Path to a logo image shown at the top of the left menu instead of the brand name (use a dark logo)." },
|
|
55
|
+
"agentCallout": { "type": "boolean", "description": "Show the 'Using an AI agent?' callout under the sidebar nav — a copy-paste prompt pointing an agent at the brand.json / tokens.json / brand.md exports. Defaults to true; set false to hide it." }
|
|
55
56
|
}
|
|
56
57
|
},
|
|
57
58
|
"fonts": {
|
package/dist/engine.js
CHANGED
|
@@ -123,6 +123,57 @@
|
|
|
123
123
|
}).join('');
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
/* ==============================================================
|
|
127
|
+
2b. Render agent callout — a paste-ready prompt that points an AI
|
|
128
|
+
agent at the machine-readable exports (brand.json / tokens.json /
|
|
129
|
+
brand.md) so it reads structured brand data instead of scraping the
|
|
130
|
+
rendered page. Opt out with brand.agentCallout === false.
|
|
131
|
+
============================================================== */
|
|
132
|
+
function renderAgentCallout() {
|
|
133
|
+
var box = document.getElementById('agent-callout');
|
|
134
|
+
if (!box) return;
|
|
135
|
+
if (cfg.brand && cfg.brand.agentCallout === false) return;
|
|
136
|
+
|
|
137
|
+
// Resolve export URLs relative to this page exactly as a link would, so
|
|
138
|
+
// the pasted prompt carries absolute URLs the agent can fetch directly.
|
|
139
|
+
// Clear any userinfo so basic-auth creds in the page URL don't leak into
|
|
140
|
+
// the copied prompt (a relative path already drops the page query/hash).
|
|
141
|
+
function exportUrl(file) {
|
|
142
|
+
var u = new URL(file, location.href);
|
|
143
|
+
u.username = ''; u.password = '';
|
|
144
|
+
return u.href;
|
|
145
|
+
}
|
|
146
|
+
var brandUrl, tokensUrl, mdUrl;
|
|
147
|
+
try {
|
|
148
|
+
brandUrl = exportUrl('brand.json');
|
|
149
|
+
tokensUrl = exportUrl('tokens.json');
|
|
150
|
+
mdUrl = exportUrl('brand.md');
|
|
151
|
+
} catch (_) {
|
|
152
|
+
brandUrl = 'brand.json'; tokensUrl = 'tokens.json'; mdUrl = 'brand.md';
|
|
153
|
+
}
|
|
154
|
+
// Strip control chars / newlines and collapse whitespace so a hostile
|
|
155
|
+
// brand name can't smuggle instructions into the paste-ready agent prompt.
|
|
156
|
+
var name = ((cfg.brand && (cfg.brand.displayName || cfg.brand.name)) || 'this brand')
|
|
157
|
+
.replace(/[\u0000-\u001F\u007F\u00AD\u200B-\u200F\u202A-\u202E\u2060-\u2069\uFEFF]/g, ' ').replace(/\s+/g, ' ').trim() || 'this brand';
|
|
158
|
+
var prompt =
|
|
159
|
+
'This page is a brandkit brand guide for ' + name + '. It publishes ' +
|
|
160
|
+
'machine-readable brand data — read these instead of scraping the page:\n\n' +
|
|
161
|
+
'- ' + brandUrl + ' — full structured brand: colors (roles + contrast), typography, voice, logos, spacing\n' +
|
|
162
|
+
'- ' + tokensUrl + ' — W3C design tokens (DTCG $type/$value), for code and design tooling\n' +
|
|
163
|
+
'- ' + mdUrl + ' — brand brief: how to stay on-brand\n\n' +
|
|
164
|
+
'Fetch them, then apply ' + name + "'s colors, type, and voice to what you're building.";
|
|
165
|
+
|
|
166
|
+
box.innerHTML =
|
|
167
|
+
'<div class="sidebar-agent-title">Using an AI agent?</div>' +
|
|
168
|
+
'<p class="sidebar-agent-desc">Paste this so it reads the brand data, not the page.</p>' +
|
|
169
|
+
'<button type="button" class="sidebar-agent-btn" id="agent-callout-btn">Copy agent prompt</button>';
|
|
170
|
+
// Set the payload via property (not an HTML attribute) so no font/brand
|
|
171
|
+
// value needs escaping and newlines survive intact.
|
|
172
|
+
var btn = box.querySelector('#agent-callout-btn');
|
|
173
|
+
if (btn) btn.dataset.copy = prompt;
|
|
174
|
+
box.hidden = false;
|
|
175
|
+
}
|
|
176
|
+
|
|
126
177
|
/* ==============================================================
|
|
127
178
|
3. Render colors
|
|
128
179
|
============================================================== */
|
|
@@ -686,6 +737,13 @@
|
|
|
686
737
|
copyText(codeLine.dataset.copy);
|
|
687
738
|
return;
|
|
688
739
|
}
|
|
740
|
+
|
|
741
|
+
// Agent callout prompt
|
|
742
|
+
var agentBtn = e.target.closest('#agent-callout-btn');
|
|
743
|
+
if (agentBtn) {
|
|
744
|
+
copyText(agentBtn.dataset.copy);
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
689
747
|
});
|
|
690
748
|
}
|
|
691
749
|
|
|
@@ -886,6 +944,7 @@
|
|
|
886
944
|
bootstrap();
|
|
887
945
|
renderShell();
|
|
888
946
|
renderNav();
|
|
947
|
+
renderAgentCallout();
|
|
889
948
|
renderSectionIntros();
|
|
890
949
|
renderColors();
|
|
891
950
|
renderGradients();
|
package/dist/index.html
CHANGED
package/dist/styles.css
CHANGED
|
@@ -129,11 +129,49 @@ body {
|
|
|
129
129
|
.sidebar-nav a:hover { color: var(--ink); background: var(--cloud); }
|
|
130
130
|
.sidebar-nav a.active { color: var(--accent-text); border-left-color: var(--accent-text); background: rgba(var(--accent-rgb), 0.04); font-weight: 500; }
|
|
131
131
|
|
|
132
|
+
/* Agent callout — paste-ready prompt that points an AI agent at the exports */
|
|
133
|
+
.sidebar-agent {
|
|
134
|
+
margin: 28px 16px 8px;
|
|
135
|
+
padding: 14px;
|
|
136
|
+
border: 1px solid var(--mist);
|
|
137
|
+
border-radius: 12px;
|
|
138
|
+
background: rgba(var(--accent-rgb), 0.04);
|
|
139
|
+
}
|
|
140
|
+
.sidebar-agent-title {
|
|
141
|
+
font-size: 12px;
|
|
142
|
+
font-weight: 600;
|
|
143
|
+
color: var(--ink);
|
|
144
|
+
margin-bottom: 4px;
|
|
145
|
+
}
|
|
146
|
+
.sidebar-agent-desc {
|
|
147
|
+
font-size: 11px;
|
|
148
|
+
line-height: 1.4;
|
|
149
|
+
color: var(--slate);
|
|
150
|
+
margin: 0 0 10px;
|
|
151
|
+
}
|
|
152
|
+
.sidebar-agent-btn {
|
|
153
|
+
display: block;
|
|
154
|
+
width: 100%;
|
|
155
|
+
padding: 7px 10px;
|
|
156
|
+
font-size: 12px;
|
|
157
|
+
font-weight: 500;
|
|
158
|
+
font-family: inherit;
|
|
159
|
+
color: var(--primary-foreground);
|
|
160
|
+
background: var(--primary);
|
|
161
|
+
border: none;
|
|
162
|
+
border-radius: 8px;
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
transition: filter 150ms ease;
|
|
165
|
+
}
|
|
166
|
+
.sidebar-agent-btn:hover { filter: brightness(0.9); }
|
|
167
|
+
.sidebar-agent-btn:active { transform: translateY(1px); }
|
|
168
|
+
.sidebar-agent-btn:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
|
|
169
|
+
|
|
132
170
|
/* ── Sidebar Grouped Navigation ── */
|
|
133
171
|
.nav-group {
|
|
134
172
|
padding: 20px 24px 6px;
|
|
135
173
|
font-family: var(--font-body), sans-serif;
|
|
136
|
-
font-size:
|
|
174
|
+
font-size: 12px;
|
|
137
175
|
font-weight: 700;
|
|
138
176
|
letter-spacing: 0.10em;
|
|
139
177
|
text-transform: uppercase;
|