Files
figma-templates-showcase/scripts/match-and-update.py
kang 3237ef8271 feat: 12 套 Sketch 也上 Figma,47/47 模板全部投射就位
- 16 个 .sketch 经 Playwright Import 上传(Figma 自动转 fig)
- 匹配脚本扩展:fig 优先,sketch 次之
- 47/47 匹配(35 fig + 12 sketch-only)
- banner 文案更新

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 15:58:06 +08:00

110 lines
4.4 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Match Figma cloud Drafts files (from figma-files.json) back to W{N} entries in
manifest.json by fuzzy name match, then update web/data.json with figma_key+url.
"""
import json, re, sys, difflib
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
def normalize(s):
s = s.lower()
s = re.sub(r'[^a-z0-9]+', ' ', s).strip()
return s
def best_match(target, candidates):
"""Return (score, candidate) best match from candidates list of dicts with .name"""
nt = normalize(target)
best = (0, None)
for c in candidates:
nc = normalize(c['name'])
# exact / prefix / contains / sequence
if nt == nc: s = 1.0
elif nt in nc or nc in nt: s = 0.85
else: s = difflib.SequenceMatcher(None, nt, nc).ratio()
if s > best[0]:
best = (s, c)
return best
def main():
manifest = json.loads((ROOT/'manifest.json').read_text())
figma_files_path = ROOT/'figma-files.json'
if not figma_files_path.exists():
print(f"missing {figma_files_path}", file=sys.stderr)
sys.exit(1)
figma_files = json.loads(figma_files_path.read_text()) # list of {key, name, ...}
# Match each template (fig preferred, else sketch) against cloud files
matches = []
used_keys = set()
for t in manifest['templates']:
source_files = t['fig'] if t['fig'] else t['sketch']
if not source_files: continue
kind = 'fig' if t['fig'] else 'sketch'
targets = [Path(f).stem for f in source_files]
if t.get('archive'):
targets.append(Path(t['archive']).stem)
targets.append(t['name'])
best_overall = (0, None)
for tgt in targets:
score, cand = best_match(tgt, [f for f in figma_files if f['key'] not in used_keys])
if score > best_overall[0]:
best_overall = (score, cand)
if score > 0.95:
break
score, cand = best_overall
stem = Path(source_files[0]).stem
if cand and score >= 0.6:
used_keys.add(cand['key'])
matches.append({
'W': t['id'], 'name': t['name'], 'kind': kind, 'source_stem': stem,
'matched': cand['name'], 'key': cand['key'], 'score': round(score, 3)
})
else:
matches.append({
'W': t['id'], 'name': t['name'], 'kind': kind, 'source_stem': stem,
'matched': None, 'best_score': round(best_overall[0], 3) if cand else 0,
'best_candidate': cand['name'] if cand else None
})
# Update web/data.json
data_path = ROOT/'web'/'data.json'
data = json.loads(data_path.read_text())
by_W = {m['W']: m for m in matches if m.get('key')}
for t in data['templates']:
m = by_W.get(t['id'])
if m:
t['figma_key'] = m['key']
t['figma_url'] = f"https://www.figma.com/file/{m['key']}"
else:
t['figma_key'] = None
t['figma_url'] = None
# update banner with imported count
imported = sum(1 for t in data['templates'] if t['figma_key'])
fig_cnt = sum(1 for t in manifest['templates'] if t['fig'])
sketch_only_cnt = sum(1 for t in manifest['templates'] if not t['fig'] and t['sketch'])
data['imported_summary'] = (
f"✅ <b>{imported}/56 套</b>已云端就位在 "
f"<a href='https://www.figma.com/files/team/1304178887825899477/drafts' target='_blank'>Figma Drafts</a>"
f"{fig_cnt} 个 .fig 原生 + {sketch_only_cnt} 个 .sketch 经 Figma 转换)。"
f"点卡片 → modal → iframe 实时投射。"
)
data_path.write_text(json.dumps(data, ensure_ascii=False, indent=2))
# write match report
report = ROOT/'figma-match-report.json'
report.write_text(json.dumps(matches, ensure_ascii=False, indent=2))
total_matchable = sum(1 for t in manifest['templates'] if t['fig'] or t['sketch'])
print(f"Matched {imported}/{total_matchable} templates ({fig_cnt} fig + {sketch_only_cnt} sketch-only)")
print(f"Report: {report.relative_to(ROOT)}")
unmatched = [m for m in matches if not m.get('key')]
if unmatched:
print(f"\n⚠️ {len(unmatched)} unmatched:")
for m in unmatched:
print(f" {m['W']:4s} {m['name'][:50]:50s} best='{m.get('best_candidate','')[:40]}' score={m.get('best_score',0)}")
if __name__ == '__main__':
main()