designlang 6.0.0 → 7.1.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/.github/FUNDING.yml +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +62 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +28 -0
- package/.vercel/README.txt +11 -0
- package/.vercel/project.json +1 -0
- package/CHANGELOG.md +58 -0
- package/CONTRIBUTING.md +25 -0
- package/README.md +120 -8
- package/bin/design-extract.js +106 -3
- package/chrome-extension/README.md +41 -0
- package/chrome-extension/icons/favicon.svg +7 -0
- package/chrome-extension/icons/icon-128.png +0 -0
- package/chrome-extension/icons/icon-16.png +0 -0
- package/chrome-extension/icons/icon-32.png +0 -0
- package/chrome-extension/icons/icon-48.png +0 -0
- package/chrome-extension/manifest.json +26 -0
- package/chrome-extension/popup.html +167 -0
- package/chrome-extension/popup.js +59 -0
- package/docs/superpowers/plans/2026-04-18-designlang-v7.md +1121 -0
- package/docs/superpowers/specs/2026-04-18-designlang-v7-design.md +150 -0
- package/docs/superpowers/specs/2026-04-18-website-redesign-design.md +120 -0
- package/docs/superpowers/specs/2026-04-19-designlang-v7-1-design.md +111 -0
- package/package.json +5 -4
- package/src/config.js +26 -0
- package/src/crawler.js +136 -2
- package/src/extractors/a11y-remediation.js +47 -0
- package/src/extractors/component-clusters.js +39 -0
- package/src/extractors/css-health.js +151 -0
- package/src/extractors/scoring.js +20 -1
- package/src/extractors/semantic-regions.js +44 -0
- package/src/extractors/stack-fingerprint.js +88 -0
- package/src/formatters/_token-ref.js +44 -0
- package/src/formatters/agent-rules.js +116 -0
- package/src/formatters/android-compose.js +164 -0
- package/src/formatters/dtcg-tokens.js +175 -0
- package/src/formatters/flutter-dart.js +130 -0
- package/src/formatters/ios-swiftui.js +161 -0
- package/src/formatters/markdown.js +25 -0
- package/src/formatters/wordpress.js +183 -0
- package/src/index.js +30 -0
- package/src/mcp/resources.js +64 -0
- package/src/mcp/server.js +110 -0
- package/src/mcp/tools.js +149 -0
- package/src/utils-cookies.js +73 -0
- package/tests/cli.test.js +50 -0
- package/tests/cookies.test.js +98 -0
- package/tests/extractors.test.js +131 -0
- package/tests/formatters.test.js +232 -0
- package/tests/mcp.test.js +68 -0
- package/website/app/api/extract/route.js +216 -56
- package/website/app/components/A11ySlider.js +369 -0
- package/website/app/components/Comparison.js +286 -0
- package/website/app/components/CssHealth.js +243 -0
- package/website/app/components/HeroExtractor.js +455 -0
- package/website/app/components/Marginalia.js +3 -0
- package/website/app/components/McpSection.js +223 -0
- package/website/app/components/PlatformTabs.js +250 -0
- package/website/app/components/RegionsComponents.js +429 -0
- package/website/app/components/Rule.js +13 -0
- package/website/app/components/Specimens.js +237 -0
- package/website/app/components/StructuredData.js +144 -0
- package/website/app/components/TokenBrowser.js +344 -0
- package/website/app/components/token-browser-sample.js +65 -0
- package/website/app/globals.css +415 -633
- package/website/app/icon.svg +7 -0
- package/website/app/layout.js +113 -6
- package/website/app/opengraph-image.js +170 -0
- package/website/app/page.js +325 -148
- package/website/app/robots.js +15 -0
- package/website/app/seo-config.js +82 -0
- package/website/app/sitemap.js +18 -0
- package/website/lib/cache.js +73 -0
- package/website/lib/rate-limit.js +30 -0
- package/website/lib/rate-limit.test.js +55 -0
- package/website/lib/specimens.json +86 -0
- package/website/lib/token-helpers.js +70 -0
- package/website/lib/url-safety.js +103 -0
- package/website/lib/url-safety.test.js +116 -0
- package/website/lib/zip-files.js +15 -0
- package/website/package-lock.json +85 -0
- package/website/package.json +1 -0
- package/website/public/favicon.svg +7 -0
- package/website/public/logo-specimen.svg +76 -0
- package/website/public/mark.svg +12 -0
- package/website/public/site.webmanifest +13 -0
- package/website/app/favicon.ico +0 -0
- package/website/public/file.svg +0 -1
- package/website/public/globe.svg +0 -1
- package/website/public/next.svg +0 -1
- package/website/public/vercel.svg +0 -1
- package/website/public/window.svg +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifest_version": 3,
|
|
3
|
+
"name": "designlang",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Extract any website's complete design system — DTCG tokens, Tailwind, Figma variables, MCP server context, iOS/Android/Flutter/WordPress emitters.",
|
|
6
|
+
"author": "Manav Arya Singh",
|
|
7
|
+
"homepage_url": "https://designlang.manavaryasingh.com",
|
|
8
|
+
"action": {
|
|
9
|
+
"default_title": "Extract design system with designlang",
|
|
10
|
+
"default_popup": "popup.html",
|
|
11
|
+
"default_icon": {
|
|
12
|
+
"16": "icons/icon-16.png",
|
|
13
|
+
"32": "icons/icon-32.png",
|
|
14
|
+
"48": "icons/icon-48.png",
|
|
15
|
+
"128": "icons/icon-128.png"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"icons": {
|
|
19
|
+
"16": "icons/icon-16.png",
|
|
20
|
+
"32": "icons/icon-32.png",
|
|
21
|
+
"48": "icons/icon-48.png",
|
|
22
|
+
"128": "icons/icon-128.png"
|
|
23
|
+
},
|
|
24
|
+
"permissions": ["activeTab"],
|
|
25
|
+
"host_permissions": ["https://designlang.manavaryasingh.com/*"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=360" />
|
|
6
|
+
<title>designlang</title>
|
|
7
|
+
<link rel="icon" href="icons/favicon.svg" type="image/svg+xml" />
|
|
8
|
+
<style>
|
|
9
|
+
:root {
|
|
10
|
+
--paper: #f3f1ea;
|
|
11
|
+
--ink: #0a0908;
|
|
12
|
+
--ink-2: #403c34;
|
|
13
|
+
--ink-3: #8b8778;
|
|
14
|
+
--accent: #ff4800;
|
|
15
|
+
}
|
|
16
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
17
|
+
html, body { margin: 0; padding: 0; }
|
|
18
|
+
body {
|
|
19
|
+
width: 360px;
|
|
20
|
+
background: var(--paper);
|
|
21
|
+
color: var(--ink);
|
|
22
|
+
font-family: -apple-system, 'Segoe UI', system-ui, sans-serif;
|
|
23
|
+
font-size: 14px;
|
|
24
|
+
line-height: 1.4;
|
|
25
|
+
}
|
|
26
|
+
.pad { padding: 18px 18px 20px; }
|
|
27
|
+
.bar {
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: space-between;
|
|
31
|
+
padding: 12px 18px 10px;
|
|
32
|
+
border-bottom: 1px solid var(--ink);
|
|
33
|
+
}
|
|
34
|
+
.mono {
|
|
35
|
+
font-family: ui-monospace, 'SF Mono', Menlo, monospace;
|
|
36
|
+
font-size: 11px;
|
|
37
|
+
letter-spacing: 0.12em;
|
|
38
|
+
text-transform: uppercase;
|
|
39
|
+
color: var(--ink-2);
|
|
40
|
+
}
|
|
41
|
+
.mark {
|
|
42
|
+
display: inline-flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: 8px;
|
|
45
|
+
font-family: ui-monospace, Menlo, monospace;
|
|
46
|
+
font-weight: 600;
|
|
47
|
+
}
|
|
48
|
+
.mark svg { width: 16px; height: 16px; }
|
|
49
|
+
h1 {
|
|
50
|
+
margin: 16px 0 10px;
|
|
51
|
+
font-family: 'Iowan Old Style', Georgia, serif;
|
|
52
|
+
font-size: 22px;
|
|
53
|
+
font-weight: 400;
|
|
54
|
+
line-height: 1.1;
|
|
55
|
+
letter-spacing: -0.02em;
|
|
56
|
+
}
|
|
57
|
+
h1 em { color: var(--accent); font-style: italic; }
|
|
58
|
+
p { margin: 0 0 14px; color: var(--ink-2); }
|
|
59
|
+
.url {
|
|
60
|
+
display: block;
|
|
61
|
+
background: #fff;
|
|
62
|
+
border: 1px solid var(--ink);
|
|
63
|
+
padding: 10px 12px;
|
|
64
|
+
font: 12px ui-monospace, Menlo, monospace;
|
|
65
|
+
color: var(--ink);
|
|
66
|
+
word-break: break-all;
|
|
67
|
+
white-space: pre-wrap;
|
|
68
|
+
margin-bottom: 12px;
|
|
69
|
+
}
|
|
70
|
+
button, a.button {
|
|
71
|
+
display: inline-flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
justify-content: space-between;
|
|
74
|
+
gap: 10px;
|
|
75
|
+
width: 100%;
|
|
76
|
+
padding: 12px 14px;
|
|
77
|
+
font: 13px ui-monospace, Menlo, monospace;
|
|
78
|
+
letter-spacing: 0.03em;
|
|
79
|
+
background: var(--ink);
|
|
80
|
+
color: var(--paper);
|
|
81
|
+
border: 1px solid var(--ink);
|
|
82
|
+
box-shadow: 4px 4px 0 var(--accent);
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
text-decoration: none;
|
|
85
|
+
transition: transform 120ms, box-shadow 120ms;
|
|
86
|
+
}
|
|
87
|
+
button:hover, a.button:hover {
|
|
88
|
+
transform: translate(-1px, -1px);
|
|
89
|
+
box-shadow: 5px 5px 0 var(--accent);
|
|
90
|
+
}
|
|
91
|
+
button:active, a.button:active {
|
|
92
|
+
transform: translate(3px, 3px);
|
|
93
|
+
box-shadow: 1px 1px 0 var(--accent);
|
|
94
|
+
}
|
|
95
|
+
.row {
|
|
96
|
+
display: grid;
|
|
97
|
+
grid-template-columns: 1fr 1fr;
|
|
98
|
+
gap: 8px;
|
|
99
|
+
margin-top: 10px;
|
|
100
|
+
}
|
|
101
|
+
.secondary {
|
|
102
|
+
display: inline-flex;
|
|
103
|
+
justify-content: center;
|
|
104
|
+
padding: 9px 10px;
|
|
105
|
+
border: 1px solid var(--ink);
|
|
106
|
+
background: transparent;
|
|
107
|
+
color: var(--ink);
|
|
108
|
+
font: 11px ui-monospace, Menlo, monospace;
|
|
109
|
+
letter-spacing: 0.06em;
|
|
110
|
+
text-transform: uppercase;
|
|
111
|
+
text-decoration: none;
|
|
112
|
+
box-shadow: none;
|
|
113
|
+
}
|
|
114
|
+
.secondary:hover {
|
|
115
|
+
background: var(--ink);
|
|
116
|
+
color: var(--paper);
|
|
117
|
+
transform: none;
|
|
118
|
+
box-shadow: none;
|
|
119
|
+
}
|
|
120
|
+
.hint {
|
|
121
|
+
margin-top: 12px;
|
|
122
|
+
font: 11px ui-monospace, Menlo, monospace;
|
|
123
|
+
color: var(--ink-3);
|
|
124
|
+
line-height: 1.5;
|
|
125
|
+
}
|
|
126
|
+
.hint code { color: var(--ink); }
|
|
127
|
+
</style>
|
|
128
|
+
</head>
|
|
129
|
+
<body>
|
|
130
|
+
<div class="bar">
|
|
131
|
+
<span class="mark">
|
|
132
|
+
<svg viewBox="0 0 32 32" aria-hidden="true">
|
|
133
|
+
<rect width="32" height="32" fill="#F3F1EA"/>
|
|
134
|
+
<circle cx="13" cy="20" r="7.5" fill="none" stroke="#0A0908" stroke-width="4.5"/>
|
|
135
|
+
<rect x="19" y="4" width="4.5" height="25" fill="#0A0908"/>
|
|
136
|
+
<rect x="25" y="25" width="4" height="4" fill="#FF4800"/>
|
|
137
|
+
</svg>
|
|
138
|
+
designlang
|
|
139
|
+
</span>
|
|
140
|
+
<span class="mono">v7.0</span>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<div class="pad">
|
|
144
|
+
<h1>Read this page as a <em>design system</em>.</h1>
|
|
145
|
+
<p>Extracts DTCG tokens, Tailwind config, Figma variables, an MCP companion, and native iOS / Android / Flutter / WordPress outputs.</p>
|
|
146
|
+
|
|
147
|
+
<span class="url" id="url-display">—</span>
|
|
148
|
+
|
|
149
|
+
<button id="extract-btn">
|
|
150
|
+
Extract on designlang
|
|
151
|
+
<span>↗</span>
|
|
152
|
+
</button>
|
|
153
|
+
|
|
154
|
+
<div class="row">
|
|
155
|
+
<a class="secondary" id="copy-cli" href="#">Copy CLI</a>
|
|
156
|
+
<a class="secondary" href="https://github.com/Manavarya09/design-extract" target="_blank" rel="noopener">GitHub</a>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<div class="hint">
|
|
160
|
+
Prefer the CLI? <code>npx designlang <url></code>. MCP server:
|
|
161
|
+
<code>designlang mcp</code>.
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<script src="popup.js"></script>
|
|
166
|
+
</body>
|
|
167
|
+
</html>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// designlang Chrome extension popup script.
|
|
2
|
+
// On open, reads the active tab's URL, shows it, and wires the Extract button
|
|
3
|
+
// to hand off to designlang.manavaryasingh.com with the URL prefilled.
|
|
4
|
+
|
|
5
|
+
const SITE = 'https://designlang.manavaryasingh.com/';
|
|
6
|
+
|
|
7
|
+
function isExtractable(url) {
|
|
8
|
+
if (!url) return false;
|
|
9
|
+
try {
|
|
10
|
+
const u = new URL(url);
|
|
11
|
+
return u.protocol === 'http:' || u.protocol === 'https:';
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function getActiveTabUrl() {
|
|
18
|
+
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
19
|
+
return tabs[0]?.url || '';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function render(tabUrl) {
|
|
23
|
+
const display = document.getElementById('url-display');
|
|
24
|
+
const btn = document.getElementById('extract-btn');
|
|
25
|
+
const copy = document.getElementById('copy-cli');
|
|
26
|
+
|
|
27
|
+
if (!isExtractable(tabUrl)) {
|
|
28
|
+
display.textContent = '(open a regular https:// page to extract)';
|
|
29
|
+
btn.disabled = true;
|
|
30
|
+
btn.style.opacity = '0.55';
|
|
31
|
+
btn.style.cursor = 'not-allowed';
|
|
32
|
+
copy.setAttribute('aria-disabled', 'true');
|
|
33
|
+
copy.style.pointerEvents = 'none';
|
|
34
|
+
copy.style.opacity = '0.55';
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
display.textContent = tabUrl;
|
|
39
|
+
|
|
40
|
+
btn.addEventListener('click', () => {
|
|
41
|
+
const target = `${SITE}?url=${encodeURIComponent(tabUrl)}&source=chrome`;
|
|
42
|
+
chrome.tabs.create({ url: target });
|
|
43
|
+
window.close();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
copy.addEventListener('click', async (e) => {
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
const line = `npx designlang ${tabUrl}`;
|
|
49
|
+
try {
|
|
50
|
+
await navigator.clipboard.writeText(line);
|
|
51
|
+
copy.textContent = 'Copied';
|
|
52
|
+
setTimeout(() => { copy.textContent = 'Copy CLI'; }, 1200);
|
|
53
|
+
} catch {
|
|
54
|
+
copy.textContent = 'Clipboard denied';
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getActiveTabUrl().then(render);
|