Skip to content
Merged
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
18 changes: 0 additions & 18 deletions app/figma-plugin/src/ui.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@
</head>
<body>
<div class="container">
<!-- Header -->
<div class="header">
<span class="header-logo">CanICode</span>
<span class="header-sub">Design Readiness Checker</span>
</div>

<!-- Action buttons -->
<div class="btn-group">
<button class="btn btn-primary" id="btn-selection" onclick="analyzeSelection()">Analyze Selection</button>
Expand All @@ -37,15 +31,6 @@ <h2>Ready to analyze</h2>
<!-- Results — rendered by CanICode.renderReportBody() -->
<div id="results"></div>

<!-- Footer -->
<div class="footer" id="footer" style="display:none">
<div>Generated by <strong>CanICode</strong> <span style="opacity:0.5">v/* __VERSION__ */</span></div>
<div class="footer-links">
<a href="https://github.com/let-sunny/canicode/issues" target="_blank">Feedback</a>
<span style="opacity:0.3">&middot;</span>
<a href="https://github.com/let-sunny/canicode/discussions/new?category=share-your-figma" target="_blank">Share your Figma</a>
</div>
</div>
</div>

<!-- Monitoring: lightweight inline PostHog + Sentry via fetch -->
Expand Down Expand Up @@ -103,7 +88,6 @@ <h2>Ready to analyze</h2>
function showLoading() {
document.getElementById('empty-state').style.display = 'none';
document.getElementById('results').className = '';
document.getElementById('footer').style.display = 'none';
document.getElementById('loading').style.display = 'block';
document.getElementById('error').style.display = 'none';
document.getElementById('btn-selection').disabled = true;
Expand All @@ -112,7 +96,6 @@ <h2>Ready to analyze</h2>
function showError(msg) {
document.getElementById('loading').style.display = 'none';
document.getElementById('results').className = '';
document.getElementById('footer').style.display = 'none';
document.getElementById('empty-state').style.display = 'none';
var errEl = document.getElementById('error');
errEl.className = 'error-msg';
Expand All @@ -138,7 +121,6 @@ <h2>Ready to analyze</h2>
});
el.className = 'visible';
CanICode.initReportInteractions(el);
document.getElementById('footer').style.display = '';
}

// ---- Focus node in Figma — intercept all [data-node-id] clicks ----
Expand Down
25 changes: 12 additions & 13 deletions app/shared/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -277,19 +277,6 @@ body {
margin-bottom: 24px;
position: relative;
}
@media (max-width: 600px) {
.rpt-tab-list::after {
content: "";
position: sticky;
right: 0;
width: 40px;
min-height: 100%;
background: linear-gradient(to right, transparent, var(--bg));
pointer-events: none;
flex-shrink: 0;
margin-left: -40px;
}
}
.rpt-tab-list {
display: flex;
gap: 4px;
Expand Down Expand Up @@ -542,6 +529,18 @@ body {
color: rgba(113,113,122,0.6);
margin-top: 4px;
}
.rpt-footer-links {
margin-top: 4px;
font-size: 12px;
}
.rpt-footer-links a {
color: var(--fg-muted);
text-decoration: none;
}
.rpt-footer-links a:hover {
color: var(--fg);
text-decoration: underline;
}

/* ================================================================
4. Responsive — narrow viewport (Figma plugin ~420px)
Expand Down
27 changes: 13 additions & 14 deletions app/web/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
}
.web-topbar-logo { font-weight: 600; font-size: 14px; letter-spacing: -0.01em; }
.web-topbar-sub { color: #a1a1aa; font-size: 14px; }
.web-topbar a { color: #a1a1aa; text-decoration: none; transition: color 0.15s; }
.web-topbar a:hover { color: white; }
.web-topbar a { color: #a1a1aa; text-decoration: none; display: flex; align-items: center; }
.web-auth { display: flex; align-items: center; gap: 8px; }
.web-auth-dot { width: 6px; height: 6px; border-radius: 50%; }
.web-auth-dot.ok { background: #22c55e; }
Expand All @@ -47,7 +46,7 @@
.web-modal {
background: var(--card); border: 1px solid var(--border);
border-radius: var(--radius); box-shadow: 0 8px 30px rgba(0,0,0,0.12);
width: 100%; max-width: 420px; margin: 0 16px; padding: 24px;
width: 100%; max-width: 500px; margin: 0 16px; padding: 24px;
}
.web-modal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.web-modal-header h2 { font-size: 18px; font-weight: 600; }
Expand Down Expand Up @@ -124,11 +123,11 @@
<header class="web-topbar">
<div class="web-topbar-inner">
<span class="web-topbar-logo">CanICode</span>
<span class="web-topbar-sub">Figma Design Analysis</span>
<span class="web-topbar-sub">Figma AI-Readiness Checker</span>

<!-- GitHub link -->
<a href="https://github.com/let-sunny/canicode" target="_blank" rel="noopener" title="GitHub" style="margin-left:auto">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
<svg width="20" height="20" viewBox="0 0 24 24" fill="white"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
</a>

<!-- Token Authorize -->
Expand All @@ -152,27 +151,24 @@ <h2>Authorize</h2>
<div>
<label for="auth-token-input" class="web-input-label">Figma Personal Access Token</label>
<input id="auth-token-input" type="password" placeholder="figd_..." class="web-input">
<p class="web-hint">
<svg width="12" height="12" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/></svg>
Stored in your browser session only. Sent directly from your browser to Figma when you analyze or post a comment.
</p>
<p class="web-hint" style="margin-top:8px">
<p class="web-hint" style="margin-top:8px;font-size:11px;white-space:nowrap">
Figma &rarr; Settings &rarr; Security &rarr; Personal access tokens &rarr; Generate new token
</p>
</div>
<div class="web-modal-actions">
<button onclick="saveAuth()" class="btn-primary">Authorize</button>
<button onclick="clearAuth()" class="btn-secondary">Logout</button>
<button id="auth-logout-btn" onclick="clearAuth()" class="btn-secondary" style="display:none">Logout</button>
</div>
<p class="web-hint" style="margin-top:8px;font-size:11px">Stored in your browser only. Requests go directly to Figma.</p>
</div>
</div>

<main class="web-main">

<!-- Hero -->
<section class="web-hero">
<h1>Analyze your Figma designs</h1>
<p>Check development-friendliness and AI-readiness scores. Analysis runs in your browser, and requests go directly to Figma rather than through an app backend.</p>
<h1>Is your Figma design AI-ready?</h1>
<p>16 rules across 6 categories score how accurately AI can implement your design. Runs entirely in your browser.</p>
<p>
<a href="https://github.com/let-sunny/canicode/discussions/categories/share-your-figma" target="_blank" rel="noopener" class="web-hero-link">
Share your Figma design to help improve scoring accuracy
Expand Down Expand Up @@ -258,14 +254,17 @@ <h1>Analyze your Figma designs</h1>
var token = getToken();
var dot = document.getElementById('auth-dot');
var label = document.getElementById('auth-label');
var logoutBtn = document.getElementById('auth-logout-btn');
if (token) {
dot.className = 'web-auth-dot ok';
label.textContent = 'Authorized';
label.className = 'web-auth-label ok';
if (logoutBtn) logoutBtn.style.display = '';
} else {
dot.className = 'web-auth-dot no';
label.textContent = 'Not authorized';
label.className = 'web-auth-label';
if (logoutBtn) logoutBtn.style.display = 'none';
}
}

Expand Down Expand Up @@ -388,7 +387,7 @@ <h1>Analyze your Figma designs</h1>
var errMsg = res.status === 400 ? 'Bad request — check node ID format' : res.status === 403 ? 'Token lacks file access' : res.status === 404 ? 'File not found' : res.status === 429 ? 'Rate limited — try again later' : 'HTTP ' + res.status;
throw new Error(errMsg + (errBody ? ': ' + errBody.slice(0, 100) : ''));
}
btn.textContent = 'Sent \u2713';
btn.textContent = 'Sent';
btn.classList.remove('rpt-btn-fail');
btn.classList.add('rpt-btn-ok');
window._trackEvent && window._trackEvent('cic_comment_posted', {});
Expand Down
7 changes: 4 additions & 3 deletions src/core/adapters/figma-url-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ export function toCommentableNodeId(nodeId: string): string {
}

export function buildFigmaDeepLink(fileKey: string, nodeId: string): string {
// Figma URLs use hyphens instead of colons: "3010:7457" → "3010-7457"
const urlNodeId = nodeId.replace(/:/g, "-");
return `https://www.figma.com/design/${fileKey}?node-id=${encodeURIComponent(urlNodeId)}`;
// Strip instance-internal path to top-level node:
// "I175:7425;1442:7704" → "175:7425" → "175-7425"
const topNodeId = toCommentableNodeId(nodeId).replace(/:/g, "-");
return `https://www.figma.com/design/${fileKey}?node-id=${topNodeId}`;
}
2 changes: 1 addition & 1 deletion src/core/report-html/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function renderFigmaCommentScript(figmaToken: string): string {
const errMsg = res.status === 400 ? 'Bad request' : res.status === 403 ? 'Token lacks file access' : res.status === 404 ? 'File not found' : res.status === 429 ? 'Rate limited' : 'HTTP ' + res.status;
throw new Error(errMsg + (errBody ? ': ' + errBody.slice(0, 100) : ''));
}
btn.textContent = 'Sent \\u2713';
btn.textContent = 'Sent';
btn.classList.remove('rpt-btn-fail');
btn.classList.add('rpt-btn-ok');
} catch (e) {
Expand Down
4 changes: 3 additions & 1 deletion src/core/report-html/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import type { Category } from "../contracts/category.js";
import type { AnalysisIssue } from "../engine/rule-engine.js";
import type { ScoreReport } from "../engine/scoring.js";
import { version as VERSION } from "../../../package.json";
import { buildFigmaDeepLink } from "../adapters/figma-url-parser.js";
import {
CATEGORIES,
Expand Down Expand Up @@ -126,8 +127,9 @@ ${ruleGroups.length === 0

<!-- Footer -->
<footer class="rpt-footer">
<p class="rpt-footer-main">Generated by <strong>CanICode</strong></p>
<p class="rpt-footer-main"><strong>CanICode</strong> <span style="opacity:0.5">v${VERSION}</span></p>
<p class="rpt-footer-meta">${new Date().toLocaleString()} · ${data.nodeCount} nodes · Max depth ${data.maxDepth}</p>
<p class="rpt-footer-links"><a href="https://github.com/let-sunny/canicode/issues" target="_blank" rel="noopener">Feedback</a> <span style="opacity:0.3">&middot;</span> <a href="https://github.com/let-sunny/canicode/discussions/new?category=share-your-figma" target="_blank" rel="noopener">Share your Figma</a></p>
</footer>`;
}

Expand Down
Loading