knowledge-site-creator
npx skills add https://github.com/joeseesun/knowledge-site-creator --skill knowledge-site-creator
Agent 安装分布
Skill 文档
Knowledge Site Creator – éç¨ç¥è¯å¦ä¹ ç½ç«çæå¨
AIç解主é¢ï¼èªå¨åä½å 容ï¼çæç½ç«ï¼ä¸é®é¨ç½²ã
æ ¸å¿ç念
设计系ç»ä¼å ï¼
- å¤ç¨è®¾è®¡è¯è¨ï¼æç®ä¸»ä¹ãé è²ãå¸å±ãäº¤äºæ¨¡å¼ï¼
- ä¸å¤ç¨å ·ä½é¡µé¢ä»£ç
- AIæ ¹æ®ä¸»é¢éæ°å使æå 容
éç¨å¦ä¹ 模å¼ï¼æ ¸å¿åè½ï¼ï¼
- éªå¡ï¼Flashcardï¼ – å¿«éè®°å¿
- å¦ä¹ ï¼Learnï¼ – æ¸è¿å¼å¦ä¹
- æµè¯ï¼Quizï¼ – ç¥è¯æ£éª
- ç´¢å¼ï¼Indexï¼ – å¿«éæ¥æ¾
- è¿åº¦ï¼Progressï¼ – å¦ä¹ 追踪
é¶æ¨¡æ¿ä¾èµï¼
- ä¸å
cp -rå¤å¶æ¨¡æ¿ - AIåè设计系ç»ï¼çææ°é¡µé¢
- ææææ¡ãç»è®¡ãä»ç»é½ç±AIåä½
è§¦åæ¹å¼
- “çæä¸ä¸ªXXXå¦ä¹ ç½ç«”
- “å建XXXç¥è¯ç½ç«”
- “å个XXXå¦ä¹ å·¥å”
示ä¾ï¼
- “çæä¸ä¸ªè¿åå¿ç妿¦å¿µå¦ä¹ ç½ç«”
- “å建éååå¦åºç¡æ¦å¿µç½ç«”
- “å个ä¸å»ç»ç»ç©´ä½å¦ä¹ å·¥å”
工使µç¨
ç¨æ·è§è§ï¼ä¸å¥è¯ï¼
ç¨æ·ï¼"çæä¸ä¸ªè¿åå¿çå¦å¦ä¹ ç½ç«"
AIèªå¨æ§è¡ï¼
â åæ"è¿åå¿çå¦"ç¹ç¹åä»·å¼
â çæ30ä¸ªæ ¸å¿æ¦å¿µæ°æ®
â åä½é¦é¡µææ¡ãç»è®¡ãä»ç»
â åè设计系ç»çæé¡µé¢
â é¨ç½²å° Vercel
â è¿åï¼https://evolutionary-psychology.vercel.app
宿ï¼
宿½æµç¨ï¼AIæ§è¡ï¼
Step 1: ç解主é¢
AIæ·±å ¥åæä¸»é¢ï¼è¾åºä¸»é¢åæï¼
主é¢åæ {
é¢å: "è¿åå¿çå¦",
ç¹ç¹: "è·¨å¦ç§ï¼çç©å¦+å¿çå¦ï¼ï¼è§£é人类è¡ä¸ºçåºå±é»è¾",
ä»·å¼: "ç解人æ§ãæ¹åå
³ç³»ãä¼åå³ç",
åä¼: "å¿çå¦ç±å¥½è
ãèªææåè
ãæè²å·¥ä½è
",
表达: "ç§å¦ä¸¥è°¨ + çæ´»åæ¡ä¾ï¼é¿å
妿¯æ¯è¯å ç "
}
æèé®é¢ï¼
- è¿æ¯ä»ä¹é¢åï¼ï¼å¦ç§åç±»ãç¥è¯ç¹ç¹ï¼
- 为ä»ä¹éè¦ï¼ï¼å¦ä¹ ä»·å¼ãåºç¨åºæ¯ï¼
- ç®æ å伿¯è°ï¼ï¼èæ¯ãéæ±ãçç¹ï¼
- å¦ä½è¡¨è¾¾æ´å¥½ï¼ï¼è¯è¨é£æ ¼ãæ¡ä¾éæ©ï¼
Step 2: çææ°æ® + ç½ç«é ç½®
â ï¸ å ³é®ï¼çæä¸¤ä¸ªæä»¶ï¼ä¸åªæ¯æ°æ®ï¼
2.1 çææ°æ®ï¼wordData.jsï¼
éç¨æ°æ®ç»æï¼
const WordRoots = [
{
id: 1,
root: "éåºæ§ (Adaptation)", // ç¥è¯ç¹åç§°
origin: "æ ¸å¿ç论", // åç±»/æ¥æº
meaning: "éè¿èªç¶éæ©è¿ååºçæå©ç¹å¾", // ä¸å¥è¯è§£é
description: "详ç»è¯´æï¼200-300åï¼...",
examples: [ // åºç¨æ¡ä¾/ä¾åï¼3个ï¼
{
word: "æé«ç",
meaning: "对é«å¤çææ§",
breakdown: { root: "éåºæ§" },
explanation: "详ç»è§£é..."
}
],
quiz: { // å°æµè¯ï¼4é1ï¼
question: "以ä¸åªä¸ªä¸æ¯éåºæ§çç¹å¾ï¼",
options: ["é项A", "é项B", "é项C", "é项D"],
correctAnswer: 2 // æ£ç¡®çæ¡ç´¢å¼ï¼0-3ï¼
}
}
];
çææ°éï¼é»è®¤20-30ä¸ªï¼æ ¹æ®ä¸»é¢å¤æåº¦è°æ´
2.2 çæé ç½®ï¼siteConfig.jsï¼ð
AIåä½ï¼å®å ¨éé 主é¢ï¼
const siteConfig = {
// åºç¡ä¿¡æ¯
topic: "è¿åå¿çå¦",
siteName: "è¿åå¿ç妿¦å¿µå·¥å",
itemName: "æ¦å¿µ", // å个ç¥è¯ç¹çç§°å¼
itemCount: 30,
// é¦é¡µHeroåºï¼AIåä½ï¼
hero: {
title: [
"30ä¸ªæ ¸å¿æ¦å¿µ",
"ç解人类è¡ä¸º",
"çåºå±é»è¾"
],
subtitle: "ä»éåºæ§å°é
å¶éæ©ï¼ç³»ç»ææ¡è¿åå¿ç妿 ¸å¿æ¡æ¶",
animation: {
enabled: true, // æ¯å¦æ¾ç¤ºå¨ç»
demoCount: 5 // å¨ç»å±ç¤ºå 个æ¦å¿µ
}
},
// ç»è®¡å¡çï¼AIçæï¼å¹é
主é¢ç¹ç¹ï¼
stats: [
{ value: "30", label: "æ ¸å¿æ¦å¿µ" },
{ value: "100+", label: "çæ´»åºç¨" },
{ value: "15åé", label: "æ¯æ¥å¦ä¹ " }
],
// åºé¨ä»ç»ï¼AIåä½ï¼
footer: {
tagline: "åçè§£èªå·±ä¸æ ·ç解人æ§",
description: "åºäºè¿åå¿çå¦çç§å¦æ¡æ¶ï¼ç¨30ä¸ªæ ¸å¿æ¦å¿µè§£é人类è¡ä¸ºèåççç©å¦é»è¾ãä»é
å¶éæ©å°äº²åå
³ç³»ï¼ä»ç¾¤ä½åä½å°æ
绪ååºï¼è®©ä½ çæäººæ§çæ·±å±åå ã"
},
// æé®ææ¡ï¼AIéé
ï¼
cta: {
primary: "å¼å§ç¬¬ä¸ä¸ªæ¦å¿µ â",
secondary: "éªå¡å¤ä¹ "
}
};
AIåä½ååï¼
hero.title: ç®æ´æåï¼3è¡ï¼çªåºæ ¸å¿ä»·å¼hero.subtitle: å ·ä½è¯´æå¦ä»ä¹ï¼ä¸ºä»ä¹å¦stats: çå®ãæè¯´æåçæ°åï¼å¹é 主é¢ç¹ç¹footer.tagline: ä¸å¥è¯ç¹é¢ï¼ææä¸å£footer.description: 2-3å¥ï¼è¯´æ¸ æ¥æ¯ä»ä¹ãå¦ä»ä¹ãæä»ä¹ç¨
Step 3: åè设计系ç»ï¼çæé¡µé¢
â ï¸ ä¸åå¤å¶æ¨¡æ¿ï¼AIåè设计è§èï¼çææ°é¡µé¢
3.1 设计系ç»åè
â ï¸ åèææ¡£ï¼references/design-system.md – 宿´ç设计è§è
æ ¸å¿è¦ç¹ï¼
- é è²ï¼é»è²ä¸»é¢è² (#FBBF24)ï¼ç°è²ç³»æååèæ¯
- åä½ï¼Interå使ï¼ä»£ç ç¨Courier New
- 飿 ¼ï¼æç®ä¸»ä¹ï¼å¤§çç½ï¼æ¸ æ°å±çº§
- ç»ä»¶ï¼åè§å¡çï¼12pxï¼ï¼ææµ é´å½±
- é´è·ï¼8pxç½æ ¼ç³»ç»ï¼Heroåº96pxçç½
详ç»é
è²ãåä½ãé´è·ãç»ä»¶æ ·å¼è§ design-system.md
3.2 çæé¡µé¢æ¸ å
â ï¸ åè½åèï¼
references/core-patterns.md– æ ¸å¿å¦ä¹ 模å¼å®ç°references/code-quality.md– 代ç è´¨éæ åï¼å¿ é¡»éµå®ï¼references/seo-best-practices.md– SEOä¼åæå ðreferences/pwa-setup.md– PWAé ç½®æå
代ç è´¨éè¦æ±ï¼å¼ºå¶ï¼ï¼
- â é误å¤çï¼ææ LocalStorage æä½å¿ é¡»æ try-catch
- â XSS 鲿¤ï¼ä½¿ç¨ textContent/createElementï¼ç¦æ¢ç´æ¥ innerHTML æå ¥æªè½¬ä¹æ°æ®
- â DOM å®å ¨ï¼ææ DOM æä½åæ£æ¥å ç´ åå¨
- â é¿å å ¨å±æ±¡æï¼ä½¿ç¨æ¨¡åå°è£ æ IIFE
详ç»è§åè§ references/code-quality.mdã
AIåè设计系ç»ï¼ä»é¶çæä»¥ä¸é¡µé¢ï¼
-
index.html – é¦é¡µ ð
- Heroåºï¼ä½¿ç¨
siteConfig.hero.title/subtitle - å¨ç»æ¼ç¤ºï¼ä»
WordRoots卿å è½½å5个ï¼è§core-patterns.md §9ï¼ - ç»è®¡å¡çï¼ä½¿ç¨
siteConfig.stats - CTAæé®ï¼ä½¿ç¨
siteConfig.cta - Footerï¼ä½¿ç¨
siteConfig.footer
- Heroåºï¼ä½¿ç¨
-
learn.html – å¦ä¹ 页ï¼è§core-patterns.md §5ï¼
- æ¸è¿å¼å¡çå±ç¤º
- ä¸ä¸ä¸ª/ä¸ä¸ä¸ªå¯¼èª
- æ è®°å·²ææ¡åè½
-
flashcard.html – éªå¡é¡µï¼è§core-patterns.md §4ï¼
- å¡ç翻转å¨ç»
- é®çå¿«æ·é®ï¼ââ翻页ï¼ç©ºæ ¼ç¿»è½¬ï¼
- è¿åº¦æ¾ç¤º
-
roots.html – ç´¢å¼é¡µï¼è§core-patterns.md §7ï¼
- æ é¢éé
ï¼
${itemName}ç´¢å¼ - æç´¢æ¡ + çéå¨
- å¡çç½æ ¼å¸å±
- æ é¢éé
ï¼
-
progress.html – è¿åº¦é¡µï¼è§core-patterns.md §8ï¼
- å¦ä¹ ç»è®¡
- å·²ææ¡å表
- æå°±ç³»ç»
-
root-detail.html – 详æ 页
- æ¦å¿µè¯¦ç»è¯´æ
- ä¾åå±ç¤º
- æµè¯é¢ï¼è§core-patterns.md §6ï¼
-
css/minimal.css – æ ·å¼æä»¶ï¼è§design-system.mdï¼
- ç»ä¸è®¾è®¡ç³»ç»
- ååºå¼å¸å±
-
js/storage.js – åå¨é»è¾ï¼è§core-patterns.md §3ï¼
- LocalStorage è¿åº¦ç®¡ç
-
manifest.json – PWA é ç½®ï¼è§pwa-setup.md §1ï¼ð
- App åç§°ã徿 ã主é¢è²
- æ¯æå®è£ å°ä¸»å±å¹
-
sw.js – Service Workerï¼è§pwa-setup.md §2ï¼ð
- ç¼åéæèµæº
- æ¯æç¦»çº¿è®¿é®
-
icon-192.png / icon-512.png – PWA 徿 ð
- èªå¨çæï¼ä½¿ç¨ PIL ä»é ç½®çæï¼é»è²èæ¯ + 䏻颿åï¼
- ä¸è¦æå¨å建ï¼AI åºèªå¨ç¨ Python PIL çæ
-
sitemap.xml – ç½ç«å°å¾ï¼è§seo-best-practices.md §4ï¼ð
- ååºææé¡µé¢URL
- æäº¤å°æç´¢å¼æ
-
robots.txt – ç¬è«æä»¤ï¼è§seo-best-practices.md §5ï¼ð
- å 许/ç¦æ¢æåè§å
- Sitemap ä½ç½®å£°æ
â ï¸ å¼ºå¶è¦æ±ï¼ææ HTML æä»¶å¿ é¡»å å«å®æ´ç meta æ ç¾
æ¯ä¸ª HTML æä»¶ç <head> å¿
é¡»å
å«ï¼
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${siteConfig.siteName}</title>
<!-- SEO åºç¡ -->
<meta name="description" content="${siteConfig.footer.description}">
<meta name="keywords" content="${siteConfig.topic},å¦ä¹ ,ç¥è¯,${siteConfig.itemName}">
<meta name="author" content="乿¨">
<meta name="language" content="zh-CN">
<meta name="robots" content="index, follow">
<link rel="canonical" href="${currentPageUrl}">
<!-- Open Graph (社交å享) -->
<meta property="og:title" content="${siteConfig.siteName}">
<meta property="og:description" content="${siteConfig.footer.description}">
<meta property="og:type" content="website">
<meta property="og:url" content="${currentPageUrl}">
<meta property="og:image" content="${siteBaseUrl}/icon-512.png">
<meta property="og:site_name" content="${siteConfig.siteName}">
<meta property="og:locale" content="zh_CN">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@vista8">
<meta name="twitter:creator" content="@vista8">
<meta name="twitter:title" content="${siteConfig.siteName}">
<meta name="twitter:description" content="${siteConfig.footer.description}">
<meta name="twitter:image" content="${siteBaseUrl}/icon-512.png">
<!-- Favicon (ç®åç emoji data URI) -->
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>ð</text></svg>">
<!-- PWA æ¯æ ð -->
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#FBBF24">
<!-- iOS Safari PWA æ¯æ -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="${siteConfig.itemName}å¦ä¹ ">
<link rel="apple-touch-icon" href="/icon-192.png">
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- æ ·å¼ -->
<link rel="stylesheet" href="css/minimal.css">
</head>
å ³é®ååï¼
- â æ ¸å¿å¦ä¹ 模å¼ï¼éªå¡ãå¦ä¹ ãæµè¯ï¼ä¿æä¸è´ – åè core-patterns.md
- â è®¾è®¡é£æ ¼ï¼é è²ãåä½ãå¸å±ï¼ä¿æä¸è´ – åè design-system.md
- â ææææ¡ãæ é¢ãæè¿°ç±AIæ ¹æ®ä¸»é¢åä½
- â 代ç è´¨éï¼å¿ é¡»éµå® code-quality.md æ åï¼é误å¤çãXSS鲿¤ãDOMå®å ¨ï¼ð
- â PWA æ¯æï¼manifest.json + Service Worker + 徿 ï¼ç¦»çº¿è®¿é®ãå¯å®è£ ï¼ð
- â SEO ä¼åï¼å®æ´ç meta æ ç¾ + sitemap.xml + robots.txt + ç»æåæ°æ® ð
- â è¯ä¹å HTMLï¼æ£ç¡®ä½¿ç¨ header, main, article, section çæ ç¾ ð
- â ç§»å¨ç«¯ä¼å ï¼ååºå¼è®¾è®¡ + viewport meta + å¿«éå è½½ï¼< 3ç§ï¼ð
- â ä¸è¦ç¡¬ç¼ç ç¹å®é¢åçå 容
Step 4: å建项ç®ç»æ
# 项ç®ä½ç½®
mkdir -p "/Users/joe/Dropbox/code/${topic}-workshop"
cd "/Users/joe/Dropbox/code/${topic}-workshop"
# å建ç®å½ç»æ
mkdir -p js css
# åå
¥æ°æ®
cat > js/wordData.js << 'EOF'
const WordRoots = [...];
EOF
# åå
¥é
ç½® ð
cat > js/siteConfig.js << 'EOF'
const siteConfig = {...};
EOF
# åå
¥é¡µé¢ï¼AIçæçHTMLï¼
cat > index.html << 'EOF'
[AIçæçindex.html]
EOF
# åå
¥å
¶ä»é¡µé¢...
# ð èªå¨çæ PWA 徿 ï¼ç¨ PILï¼
python3 << 'PYEOF'
from PIL import Image, ImageDraw, ImageFont
def create_icon(size, filename, text):
# å建é»è²èæ¯
img = Image.new('RGB', (size, size), color='#FBBF24')
draw = ImageDraw.Draw(img)
# å°è¯ä½¿ç¨ç³»ç»åä½
try:
font_size = int(size * 0.25)
font = ImageFont.truetype('/System/Library/Fonts/PingFang.ttc', font_size)
except:
font = ImageFont.load_default()
# è·åæåè¾¹çæ¡
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
# å±
ä¸ä½ç½®
x = (size - text_width) / 2
y = (size - text_height) / 2
# ç»å¶æåï¼æ·±ç°è²ï¼
draw.text((x, y), text, font=font, fill='#1F2937')
# ä¿å
img.save(filename, 'PNG')
# ä»ä¸»é¢çæå¾æ æåï¼åå2-3个åï¼
icon_text = "${siteConfig.itemName}"[:3] # ä¾å¦ï¼"æ¦å¿µ" â "æ¦å¿µ"ã"åå²ç¥è¯ç¹" â "åå²ç¥"
# çæä¸¤ç§å°ºå¯¸
create_icon(192, 'icon-192.png', icon_text)
create_icon(512, 'icon-512.png', icon_text)
print("â PWA 徿 çæå®æ")
PYEOF
Step 5: æ°æ®éªè¯ï¼å¼ºå¶è´¨éæ£æ¥ï¼
â ï¸ å ³é®ï¼AI çæçæ°æ®å¿ é¡»ç»è¿å®æ´éªè¯ï¼ç¡®ä¿è´¨éåä¸è´æ§
# ========================================
# é¶æ®µ 1ï¼åºç¡ç»æéªè¯
# ========================================
echo "ð éªè¯æ°æ®ç»æ..."
# 1.1 æ£æ¥æ°æ®æä»¶åå¨ä¸åéåæ£ç¡®
if ! grep -q "const WordRoots" js/wordData.js; then
echo "â éè¯¯ï¼æ°æ®åéå䏿£ç¡®ï¼åºä¸º const WordRootsï¼"
exit 1
fi
# 1.2 æ£æ¥é
ç½®æä»¶åå¨ä¸åéåæ£ç¡®
if ! grep -q "const siteConfig" js/siteConfig.js; then
echo "â é误ï¼é
ç½®æä»¶ç¼ºå¤±ï¼åºä¸º const siteConfigï¼"
exit 1
fi
# ========================================
# é¶æ®µ 2ï¼æ°æ®å®æ´æ§éªè¯
# ========================================
echo "ð éªè¯æ°æ®å®æ´æ§..."
# 2.1 ä½¿ç¨ Node.js è¿è¡æ·±åº¦éªè¯
node -e "
const fs = require('fs');
// è¯»åæ°æ®æä»¶
const dataContent = fs.readFileSync('js/wordData.js', 'utf-8');
eval(dataContent); // å è½½ WordRoots
let errors = [];
let warnings = [];
// éªè¯æ°æ®åå¨
if (typeof WordRoots === 'undefined') {
console.error('â 严éé误ï¼WordRoots æªå®ä¹');
process.exit(1);
}
if (!Array.isArray(WordRoots) || WordRoots.length === 0) {
console.error('â 严éé误ï¼WordRoots 为空æä¸æ¯æ°ç»');
process.exit(1);
}
console.log(\`ð æ°æ®éï¼\${WordRoots.length} 个ç¥è¯ç¹\`);
// éåæ¯ä¸ªç¥è¯ç¹è¿è¡éªè¯
WordRoots.forEach((item, index) => {
const itemLabel = \`Item #\${item.id || index}\`;
// å¿
éåæ®µæ£æ¥
if (!item.id) errors.push(\`\${itemLabel}: ç¼ºå° id\`);
if (!item.root || item.root.trim() === '') errors.push(\`\${itemLabel}: ç¼ºå° rootï¼ç¥è¯ç¹åç§°ï¼\`);
if (!item.origin) warnings.push(\`\${itemLabel}: ç¼ºå° originï¼åç±»ï¼\`);
if (!item.meaning || item.meaning.trim() === '') errors.push(\`\${itemLabel}: ç¼ºå° meaningï¼ç®çè§£éï¼\`);
if (!item.description || item.description.trim() === '') errors.push(\`\${itemLabel}: ç¼ºå° descriptionï¼è¯¦ç»è¯´æï¼\`);
// æè¿°é¿åº¦æ£æ¥ï¼åºè¯¥è¯¦ç»ä½ä¸è¿é¿ï¼
if (item.description && item.description.length < 50) {
warnings.push(\`\${itemLabel}: description 太çï¼<50åï¼ï¼å»ºè®®æ©å±ä¸º200-300å\`);
}
if (item.description && item.description.length > 1000) {
warnings.push(\`\${itemLabel}: description 太é¿ï¼>1000åï¼ï¼å»ºè®®ç²¾ç®\`);
}
// ä¾åæ£æ¥
if (!item.examples || !Array.isArray(item.examples)) {
errors.push(\`\${itemLabel}: ç¼ºå° examples æ°ç»\`);
} else if (item.examples.length < 3) {
errors.push(\`\${itemLabel}: examples å°äº3个ï¼å½å \${item.examples.length}ï¼\`);
} else {
// éªè¯æ¯ä¸ªä¾åçç»æ
item.examples.forEach((ex, exIndex) => {
if (!ex.word) errors.push(\`\${itemLabel}.examples[\${exIndex}]: ç¼ºå° word\`);
if (!ex.meaning) errors.push(\`\${itemLabel}.examples[\${exIndex}]: ç¼ºå° meaning\`);
if (!ex.explanation) warnings.push(\`\${itemLabel}.examples[\${exIndex}]: ç¼ºå° explanation\`);
});
}
// æµè¯é¢æ£æ¥
if (!item.quiz) {
warnings.push(\`\${itemLabel}: ç¼ºå° quizï¼æµè¯é¢ï¼\`);
} else {
if (!item.quiz.question || item.quiz.question.trim() === '') {
errors.push(\`\${itemLabel}.quiz: ç¼ºå° question\`);
}
if (!item.quiz.options || !Array.isArray(item.quiz.options)) {
errors.push(\`\${itemLabel}.quiz: ç¼ºå° options æ°ç»\`);
} else if (item.quiz.options.length !== 4) {
errors.push(\`\${itemLabel}.quiz: options å¿
é¡»æ¯4个ï¼å½å \${item.quiz.options.length}ï¼\`);
}
if (typeof item.quiz.correctAnswer !== 'number') {
errors.push(\`\${itemLabel}.quiz: correctAnswer å¿
é¡»æ¯æ°å\`);
} else if (item.quiz.correctAnswer < 0 || item.quiz.correctAnswer > 3) {
errors.push(\`\${itemLabel}.quiz: correctAnswer è¶çï¼å¿
é¡»æ¯0-3ï¼å½å \${item.quiz.correctAnswer}ï¼\`);
}
}
});
// è¾åºéªè¯ç»æ
if (errors.length > 0) {
console.error('\\nâ åç° ' + errors.length + ' 个é误ï¼');
errors.slice(0, 10).forEach(e => console.error(' - ' + e));
if (errors.length > 10) console.error(\` ... è¿æ \${errors.length - 10} 个é误\`);
process.exit(1);
}
if (warnings.length > 0) {
console.warn('\\nâ ï¸ åç° ' + warnings.length + ' 个è¦åï¼');
warnings.slice(0, 5).forEach(w => console.warn(' - ' + w));
if (warnings.length > 5) console.warn(\` ... è¿æ \${warnings.length - 5} 个è¦å\`);
}
console.log('\\nâ æ°æ®éªè¯éè¿');
" || exit 1
# ========================================
# é¶æ®µ 3ï¼é
ç½®éªè¯
# ========================================
echo "ð éªè¯é
ç½®..."
node -e "
const fs = require('fs');
const configContent = fs.readFileSync('js/siteConfig.js', 'utf-8');
eval(configContent);
if (typeof siteConfig === 'undefined') {
console.error('â siteConfig æªå®ä¹');
process.exit(1);
}
// éªè¯å¿
éåæ®µ
const required = ['topic', 'siteName', 'itemName', 'itemCount', 'hero', 'stats', 'footer', 'cta'];
const missing = required.filter(key => !siteConfig[key]);
if (missing.length > 0) {
console.error('â siteConfig 缺å°å段ï¼' + missing.join(', '));
process.exit(1);
}
// éªè¯ hero ç»æ
if (!siteConfig.hero.title || !Array.isArray(siteConfig.hero.title) || siteConfig.hero.title.length !== 3) {
console.error('â siteConfig.hero.title å¿
é¡»æ¯3è¡æ°ç»');
process.exit(1);
}
console.log('â é
ç½®éªè¯éè¿');
" || exit 1
echo ""
echo "â
ææéªè¯éè¿ï¼"
Step 6: é¨ç½²ï¼å¼ºå¶å®å ¨æ£æ¥ï¼
â ï¸ å ³é®ï¼æ¯ä¸ªé¡¹ç®å¿ é¡»ç¬ç«é¨ç½²ï¼ç»ä¸å ±äº« GitHub ä»åº
é¨ç½²æµç¨ï¼å¿ é¡»ä¸¥æ ¼æé¡ºåºæ§è¡ï¼ï¼
# ========================================
# é¶æ®µ 1ï¼é¨ç½²åå®å
¨æ£æ¥ï¼å¿
é¡»æ§è¡ï¼
# ========================================
# 1.1 æ£æ¥å¹¶ç§»é¤ Git è¿ç¨ä»åºï¼é²æ¢å
³èå°å
¶ä»é¡¹ç®çä»åºï¼
if git remote -v 2>/dev/null | grep -q 'origin'; then
echo "â ï¸ è¦åï¼æ£æµå° Git è¿ç¨ä»åºï¼ç«å³ç§»é¤ä»¥é¿å
å²çª"
git remote remove origin
echo "â å·²ç§»é¤ Git è¿ç¨ä»åº"
fi
# 1.2 åå§åæ¬å° Gitï¼ä»
æ¬å°ï¼ä¸æ¨éå° GitHubï¼
git init
git add .
git commit -m "Initial commit: ${siteName}"
# 1.3 ååºææç°æ workshop 项ç®ï¼ç¨äºåç»éªè¯ï¼
echo "ð ç°æé¡¹ç®å表ï¼"
ls -d /Users/joe/Dropbox/code/*-workshop 2>/dev/null | while read dir; do
PROJECT_NAME=$(basename "$dir")
if [ -f "$dir/.vercel/project.json" ]; then
PROJECT_ID=$(cat "$dir/.vercel/project.json" | jq -r '.projectId' 2>/dev/null || echo "unknown")
echo " - $PROJECT_NAME (projectId: $PROJECT_ID)"
fi
done
# ========================================
# é¶æ®µ 2ï¼æ§è¡é¨ç½²
# ========================================
echo "ð å¼å§é¨ç½²å° Vercel..."
vercel --prod --yes 2>&1 | tee /tmp/vercel-deploy-${projectName}.log
DEPLOY_STATUS=$?
if [ $DEPLOY_STATUS -ne 0 ]; then
echo "â é¨ç½²å¤±è´¥ï¼è¯·æ£æ¥æ¥å¿ï¼/tmp/vercel-deploy-${projectName}.log"
exit 1
fi
# ========================================
# é¶æ®µ 3ï¼é¨ç½²å强å¶éªè¯ï¼å¿
é¡»æ§è¡ï¼
# ========================================
echo ""
echo "ð é¨ç½²åéªè¯..."
# 3.1 éªè¯ projectId å·²çæ
if [ ! -f ".vercel/project.json" ]; then
echo "â éè¯¯ï¼æªæ¾å° .vercel/project.json"
exit 1
fi
NEW_PROJECT_ID=$(cat .vercel/project.json | jq -r '.projectId')
NEW_PROJECT_NAME=$(cat .vercel/project.json | jq -r '.projectName')
echo "â æ°é¡¹ç®ï¼"
echo " åç§°: $NEW_PROJECT_NAME"
echo " ID: $NEW_PROJECT_ID"
# 3.2 æåé¨ç½² URL
DEPLOY_URL=$(grep -E "Production:|https://.*vercel.app" /tmp/vercel-deploy-${projectName}.log | grep -o "https://[^ ]*vercel.app" | head -1)
echo "â é¨ç½² URL: $DEPLOY_URL"
# 3.3 éªè¯æ°ç½ç«å¯è®¿é®
echo "ð éªè¯æ°ç½ç«..."
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$DEPLOY_URL" || echo "000")
if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "304" ]; then
echo "â æ°ç½ç«å¯æ£å¸¸è®¿é® (HTTP $HTTP_STATUS)"
else
echo "â ï¸ è¦åï¼æ°ç½ç«è¿å HTTP $HTTP_STATUS"
fi
# 3.4 æ£æ¥å
¶ä»é¡¹ç®æ¯å¦åå½±åï¼å
³é®æ¥éª¤ï¼
echo ""
echo "ð æ£æ¥å
¶ä»é¡¹ç®æ¯å¦åå½±å..."
AFFECTED_PROJECTS=0
for dir in /Users/joe/Dropbox/code/*-workshop; do
if [ "$dir" = "/Users/joe/Dropbox/code/${projectName}" ]; then
continue # è·³è¿å½å项ç®
fi
if [ -f "$dir/.vercel/project.json" ]; then
OLD_PROJECT_NAME=$(basename "$dir")
OLD_PROJECT_ID=$(cat "$dir/.vercel/project.json" | jq -r '.projectId' 2>/dev/null)
# æ£æ¥æ¯å¦æç¸åç projectIdï¼è¿è¡¨ç¤ºå²çªï¼
if [ "$OLD_PROJECT_ID" = "$NEW_PROJECT_ID" ]; then
echo "â 严éé误ï¼é¡¹ç® $OLD_PROJECT_NAME ç projectId 䏿°é¡¹ç®ç¸åï¼"
echo " è¿æå³çæ°é¡¹ç®è¦çäºæ§é¡¹ç®ï¼éè¦ç«å³ä¿®å¤ã"
AFFECTED_PROJECTS=$((AFFECTED_PROJECTS + 1))
fi
fi
done
if [ $AFFECTED_PROJECTS -gt 0 ]; then
echo ""
echo "â æ£æµå° $AFFECTED_PROJECTS 个项ç®åå½±åï¼é¨ç½²å¤±è´¥ï¼"
echo " 请æå¨æ£æ¥å¹¶ä¿®å¤å²çªã"
exit 1
fi
echo "â ææç°æé¡¹ç®æªåå½±å"
# ========================================
# é¶æ®µ 3.5ï¼ç§»å¨ç«¯å SEO éªè¯ ð
# ========================================
echo ""
echo "ð± éªè¯ç§»å¨ç«¯éé
..."
# æ£æ¥ viewport meta æ ç¾ï¼ç§»å¨ç«¯å¿
éï¼
VIEWPORT_CHECK=$(curl -s "$DEPLOY_URL" | grep -c 'viewport')
if [ "$VIEWPORT_CHECK" -gt 0 ]; then
echo "â ç§»å¨ç«¯ viewport é
ç½®æ£ç¡®"
else
echo "â ï¸ è¦åï¼ç¼ºå° viewport meta æ ç¾ï¼ç§»å¨ç«¯å¯è½æ¾ç¤ºå¼å¸¸"
fi
# æ£æ¥ SEO meta æ ç¾
echo "ð éªè¯ SEO é
ç½®..."
META_DESCRIPTION=$(curl -s "$DEPLOY_URL" | grep -c 'meta name="description"')
META_OG=$(curl -s "$DEPLOY_URL" | grep -c 'property="og:')
if [ "$META_DESCRIPTION" -gt 0 ]; then
echo "â SEO description å·²é
ç½®"
else
echo "â ï¸ è¦åï¼ç¼ºå° SEO description"
fi
if [ "$META_OG" -gt 0 ]; then
echo "â Open Graph æ ç¾å·²é
ç½®ï¼ç¤¾äº¤å享ä¼åï¼"
else
echo "â ï¸ è¦åï¼ç¼ºå° Open Graph æ ç¾"
fi
# 模æç§»å¨è®¾å¤è®¿é®æµè¯
echo "ð± æ¨¡æç§»å¨è®¾å¤è®¿é®..."
MOBILE_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1" \
"$DEPLOY_URL")
if [ "$MOBILE_STATUS" = "200" ] || [ "$MOBILE_STATUS" = "304" ]; then
echo "â ç§»å¨ç«¯è®¿é®æ£å¸¸ (HTTP $MOBILE_STATUS)"
else
echo "â ï¸ è¦åï¼ç§»å¨ç«¯è®¿é®å¼å¸¸ (HTTP $MOBILE_STATUS)"
fi
# ========================================
# é¶æ®µ 4ï¼æåæ»ç»
# ========================================
echo ""
echo "â
é¨ç½²æåï¼"
echo ""
echo "ð é¨ç½²ä¿¡æ¯ï¼"
echo " 项ç®åç§°: $NEW_PROJECT_NAME"
echo " é¡¹ç® ID: $NEW_PROJECT_ID"
echo " é¨ç½² URL: $DEPLOY_URL"
echo " æ¥å¿æä»¶: /tmp/vercel-deploy-${projectName}.log"
å®å ¨ååï¼å¿ é¡»éµå®ï¼ï¼
- â ç¦æ¢ GitHub å ³èï¼é»è®¤ä¸è¿æ¥ GitHubï¼é¿å ä»åºå ±äº«
- â 强å¶åç½®æ£æ¥ï¼é¨ç½²åå¿ é¡»ç§»é¤ææ Git è¿ç¨ä»åº
- â 强å¶åç½®éªè¯ï¼é¨ç½²åå¿ é¡»æ£æ¥ projectId å¯ä¸æ§
- â å²çªèªå¨æ£æµï¼åç°å²çªç«å³æ¥éï¼ä¸å 许继ç»
- â 宿´æ¥å¿è®°å½ï¼ææé¨ç½²æä½è®°å½å° /tmp/
妿ä»ç¶åçå²çªï¼æç«¯æ åµï¼ï¼
妿éªè¯éè¿ä½å®é 仿é®é¢ï¼æ§è¡ç´§æ¥ä¿®å¤ï¼
# 1. ç«å³ååºææ Vercel 项ç®
vercel ls
# 2. æ£æ¥æ¯ä¸ªæ¬å°é¡¹ç®çé¨ç½²ç¶æ
cd /Users/joe/Dropbox/code
for dir in *-workshop; do
echo "=== $dir ==="
cd "$dir"
if [ -f ".vercel/project.json" ]; then
cat .vercel/project.json | jq -r '.projectName, .projectId'
fi
cd ..
done
# 3. éæ°é¨ç½²åå½±åç项ç®
cd /path/to/affected-project
vercel --prod --yes
# 4. åç¨æ·æ¥åå²çªè¯¦æ
åä¿®å¤ç»æ
æåè¾åºæ¨¡æ¿
â
${siteName} å·²çæå¹¶é¨ç½²ï¼
ð 项ç®ä½ç½®ï¼${projectPath}
ð ç½ç«åç§°ï¼${siteName}
ð ç¥è¯ç¹æ°éï¼${itemCount}个
ð 访é®é¾æ¥ï¼${deployUrl}
ð¯ æ ¸å¿ç¹æ§ï¼
- â
AIåä½é¦é¡µï¼æ ¹æ®ä¸»é¢çææ é¢ã坿 é¢ãç»è®¡
- â
卿å¨ç»ï¼èªå¨ä»æ°æ®å è½½ï¼å®å
¨éé
- â
éç¨å¦ä¹ 模å¼ï¼éªå¡ãæ¸è¿å¦ä¹ ãæµè¯ãç´¢å¼
- â
æç®è®¾è®¡ï¼æ¸
æ°çè§è§å±çº§ï¼ä¸æ³¨å
容
ð§ ä¸ä¸æ¥ï¼
1. æå¼ç½ç«æ¥çææ
2. å®¡æ ¸AIçæçå
容
3. é
ç½®èªå®ä¹ååï¼Vercelåå°ï¼
宿½æ£æ¥æ¸ å
AI æ§è¡æ¤ skill æ¶ï¼å¿ é¡»ä¸¥æ ¼æé¡ºåºå®æï¼
- 1. çè§£ä¸»é¢ – åæé¢åç¹ç¹ãä»·å¼ãåä¼ã表达æ¹å¼
- 2. çææ°æ® – å建 wordData.jsï¼const WordRootsï¼
- 3. çæé ç½® ð – å建 siteConfig.jsï¼AIåä½é¦é¡µææ¡ï¼
- 4. çæé¡µé¢ ð – åè设计系ç»ï¼ä»é¶çæHTMLï¼ä¸å¤å¶æ¨¡æ¿ï¼
- 5. åå»ºé¡¹ç® – mkdir + åå ¥æææä»¶
- 6. éªè¯æ°æ® – æ£æ¥æ°æ®åé ç½®æä»¶å®æ´æ§
- 7. å®å ¨é¨ç½² ð – æ§è¡ Step 6 ç宿´é¨ç½²æµç¨ï¼å«åç½®æ£æ¥ + é¨ç½² + åç½®éªè¯ï¼
- 8. è¿åä¿¡æ¯ – 项ç®è·¯å¾ + URL + æ ¸å¿ç¹æ§ + å®å ¨æ£æ¥ç»æ
å ³é®æ¹è¿ï¼ç¸æ¯æ§çï¼
â æ§çé®é¢
- ä¾èµæ¨¡æ¿å¤å¶ï¼
cp -r word-root-workshopï¼ - ç¨ sed ç²æ´æ¿æ¢ææ¡
- é¦é¡µææ¡ç¡¬ç¼ç ï¼ä¸éé 主é¢
- å¨ç»ç¤ºä¾åæ»è±æåè¯
â æ°çä¼å¿
- é¶æ¨¡æ¿ä¾èµï¼AIä»é¶çæé¡µé¢
- AIç解主é¢ååä½ææææ¡
- é¦é¡µå®å ¨éé 主é¢ç¹ç¹
- å¨ç»èªå¨ä»æ°æ®å è½½
ð¯ æ ¸å¿ç念转å
æ§çï¼å¤å¶ + æ¿æ¢
æ°çï¼çè§£ + åä½
æ§çï¼æ¨¡æ¿é©±å¨
æ°çï¼è®¾è®¡ç³»ç»é©±å¨
æ§çï¼ç¡¬ç¼ç ææ¡
æ°çï¼AIåä½å
容
注æäºé¡¹
â ï¸ æ°æ®ç»æä¸åï¼
- ä»ç¶ä½¿ç¨
const WordRootsååºå®åæ®µç»æ - è¿æ¯æ ¸å¿å¦ä¹ 模å¼ï¼éªå¡ãå¦ä¹ ãæµè¯ï¼çåºç¡
â ï¸ è®¾è®¡é£æ ¼ä¿æï¼
- æç®ä¸»ä¹ãé»è²ä¸»é¢è²ãInteråä½
- è¿äºæ¯åçè¯å«åº¦çä¿è¯
â ï¸ AIèªç±åæ¥ï¼
- é¦é¡µææ¡ãç»è®¡æ°æ®ãä»ç»ææ¬
- æ ¹æ®ä¸»é¢ç¹ç¹åä½ï¼ä¸è¦åç¯ä¸å¾
Vercel é¨ç½²æä½³å®è·µ ð
é®é¢èæ¯
Vercel å¨é¨ç½²æ¶å¯è½ä¼èªå¨è¿æ¥ GitHub ä»åºï¼å¯¼è´å¤ä¸ªé¡¹ç®å ±äº«åä¸ä¸ªä»åºï¼å¼åé¨ç½²å²çªï¼
- æ°é¡¹ç®è¦çæ§é¡¹ç®çé¨ç½²
- æ§é¡¹ç®ç URL 失æ
- GitHub ä»åºå ³èæ··ä¹±
è§£å³æ¹æ¡
1. é»è®¤ä¸è¿æ¥ GitHub
# ä»
ä½¿ç¨æ¬å° Gitï¼ä¸æ¨éå° GitHub
git init
git add .
git commit -m "Initial commit"
vercel --prod --yes # åªé¨ç½²ï¼ä¸è¿æ¥ GitHub
2. é¨ç½²åéªè¯
# æ£æ¥çæç projectId æ¯å¦å¯ä¸
cat .vercel/project.json
# åºè¯¥çå°ç±»ä¼¼ï¼
# {"projectId":"prj_UNIQUE_ID_HERE",...}
3. åç°å²çªæ¶çè¡¥æ
妿é¨ç½²ååç°æ§é¡¹ç®åå½±åï¼
# ç«å³è¿å
¥æ§é¡¹ç®ç®å½
cd /Users/joe/Dropbox/code/æ§é¡¹ç®åç§°
# éæ°é¨ç½²æ§é¡¹ç®
vercel --prod --yes
# 确认æ§é¡¹ç®æ¢å¤æ£å¸¸
curl -I https://æ§é¡¹ç®URL
æ éææ¥æ¸ å
é¨ç½²æ°é¡¹ç®åï¼å¿ é¡»æ£æ¥ï¼
- æ°é¡¹ç®ç
.vercel/project.jsonä¸çprojectIdæ¯å¦å¯ä¸ - æ°é¡¹ç®ç Production URL æ¯å¦å¯ä»¥è®¿é®ï¼HTTP 200ï¼
- æ§é¡¹ç®ï¼å¦æåå¨ï¼ç URL æ¯å¦ä»ç¶å¯è®¿é®
- é¨ç½²æ¥å¿ä¸ç “Linked to” ä¿¡æ¯æ¯å¦æ£ç¡®
ç»éªæè®ï¼çå®çäº§äºæ ï¼
äºæ æ¶é´çº¿ï¼2026-02-25
äºæ æè¿°ï¼
- çæ
evolutionary-psychology-workshopï¼è¿åå¿çå¦ï¼ï¼æåé¨ç½² - çæ
design-aesthetics-workshopï¼è®¾è®¡ç¾å¦ï¼ï¼æåé¨ç½² - ç¨æ·åç° word.qiaomu.aiï¼åè¯æ ¹è¯ç¼ç½ç«ï¼æ¾ç¤ºçæ¯è¿åå¿çå¦å 容
- æ£æ¥åç°
word-root-workshop项ç®ç Git ä»åºè¢«è¿åå¿çå¦å 容è¦ç
æ ¹æ¬åå åæï¼
# äºæ
åçç¶æ
evolutionary-psychology-workshop â origin: https://github.com/joeseesun/word-root-workshop.git
word-root-workshop â origin: https://github.com/joeseesun/word-root-workshop.git
âââ 两个项ç®å
±äº«åä¸ä¸ª GitHub ä»åº
为ä»ä¹ä¼åçï¼
- æ§ç skill 使ç¨
cp -r word-root-workshopå¤å¶æ¨¡æ¿ - å¤å¶æ¶è¿
.git/ç®å½ä¹ä¸èµ·å¤å¶äºï¼å å«è¿ç¨ä»åºé ç½®ï¼ - é¨ç½²æ¶ Vercel æ£æµå° Git è¿ç¨ä»åºï¼èªå¨å ³è
- å¤ä¸ªé¡¹ç®å ³èåä¸ä¸ª GitHub ä»åºï¼åé¨ç½²çè¦çå é¨ç½²ç
æå®³èå´ï¼
- â word.qiaomu.aiï¼ç产ååï¼æ¾ç¤ºé误å 容
- â word-root-workshop ç Git åå²è¢«æ±¡æ
- â ç¨æ·ä½éªåæï¼éè¦ç´§æ¥ä¿®å¤
ç´§æ¥ä¿®å¤æ¥éª¤ï¼
# 1. æ¢å¤ word-root-workshop å°åå§ç¶æ
cd /Users/joe/Dropbox/code/word-root-workshop
git log --oneline # æ¾å°åå§æäº¤
git reset --hard 14cc7b0 # æ¢å¤å°åå§è¯æ ¹è¯ç¼å
容
# 2. ä¿®å¤ vercel.json é
ç½®å²çª
# ç§»é¤ä¸å
¼å®¹ç routes é
ç½®
# 3. éæ°é¨ç½²
vercel --prod --yes
# 4. éªè¯æ¢å¤
curl -sL https://word.qiaomu.ai/ | grep "è¯æ ¹è¯ç¼è®°å¿å·¥å"
# 5. æ¸
çå
¶ä»é¡¹ç®ç Git è¿ç¨ä»åº
cd /Users/joe/Dropbox/code/evolutionary-psychology-workshop
git remote remove origin
å½»åºè§£å³æ¹æ¡ï¼å·²å¨ Step 6 宿½ï¼ï¼
- 强å¶åç½®æ£æ¥ï¼é¨ç½²åèªå¨ç§»é¤ææ Git è¿ç¨ä»åº
- 强å¶åç½®éªè¯ï¼é¨ç½²åæ£æ¥ projectId å¯ä¸æ§
- å²çªèªå¨æ£æµï¼é忿项ç®ï¼åç°ç¸å projectId ç«å³æ¥é
- 宿´æ¥å¿è®°å½ï¼ææé¨ç½²æä½è®°å½å° /tmp/
- é¶å®¹å¿çç¥ï¼ä»»ä½æ£æµå°çå²çªé½ä¸å 许继ç»
é¿æé²èæªæ½ï¼
- â
åºå¼æ¨¡æ¿å¤å¶æºå¶ï¼
cp -rï¼ï¼æ¹ç¨ä»é¶çæ - â å¨ Step 6 ä¸å®æ½å¼ºå¶å®å ¨æ£æ¥
- â æ´æ°å®æ½æ£æ¥æ¸ åï¼æç¡®”å®å ¨é¨ç½²”æ¥éª¤
- â ææ¡£ä¸å¢å “ç»éªæè®”ç« èï¼é²æ¢å人éè¹è¦è¾
æè®æ»ç»ï¼
“Copy + Paste æ¯ä¸æ¶ä¹æºã模æ¿é©±å¨ç似髿ï¼å®ååä¸äºéæ£ãåªæä»é¶çæï¼è®¾è®¡ç³»ç»é©±å¨ï¼ï¼æè½ç¡®ä¿æ¯ä¸ªé¡¹ç®çæ£ç¬ç«ã”
å½±åï¼
- ä¿ä½¿ skill 仔模æ¿é©±å¨”å½»åºéæä¸º”设计系ç»é©±å¨”
- ç¡®ç«äº”é¶æ¨¡æ¿ä¾èµ”çæ ¸å¿åå
- 建ç«äºå®åçé¨ç½²å®å ¨æ£æ¥æºå¶
æ¹éæ´æ°æºå¶ ð
使ç¨åºæ¯
å½ skill çè®¾è®¡ç³»ç»ææ´æ°ï¼å¦ CSS bug ä¿®å¤ãæ ·å¼æ¹è¿ï¼æ¶ï¼éè¦å°æ´æ°åæ¥å°ææå·²é¨ç½²ç workshop 项ç®ã
å ¸ååºæ¯ï¼
- CSS æ ·å¼ä¿®å¤ï¼ä¿®å¤äºååºå¼å¸å±é®é¢
- 设计æ¹è¿ï¼ä¼åäºå¡çé´å½±ãé´è·ãé è²
- åè½å¢å¼ºï¼æ·»å äºæ°ç交äºå¨æ
- å®å ¨æ´æ°ï¼ä¿®å¤äº XSS æ¼æ´æå ¶ä»å®å ¨é®é¢
æ´æ°èæ¬
èæ¬ä½ç½®ï¼scripts/update-css.sh
ä½¿ç¨æ¹æ³ï¼
# 1. æ¼ç»æ¨¡å¼ï¼ä»
ååºå°æ´æ°ç项ç®ï¼
bash scripts/update-css.sh --dry-run
# 2. æ§è¡æ´æ°
bash scripts/update-css.sh
工使µç¨
èæ¬èªå¨æ§è¡ä»¥ä¸æ¥éª¤ï¼
- æ«æé¡¹ç®ï¼èªå¨æ«æ
/Users/joe/Dropbox/code/*-workshop - æºè½å¯¹æ¯ï¼ä½¿ç¨
cmpå½ä»¤å¯¹æ¯ CSS æä»¶ï¼è·³è¿å·²æ¯ææ°çæ¬çé¡¹ç® - å®å
¨å¤ä»½ï¼æ´æ°åèªå¨å¤ä»½æ§ CSS 为
.backupæä»¶ - Git æäº¤ï¼èªå¨ commit CSS åæ´ï¼commit message:
chore: update CSS from skill templateï¼ - éæ°é¨ç½²ï¼è°ç¨
vercel --prod --yeséæ°é¨ç½²å°ç产ç¯å¢ - å¤±è´¥åæ»ï¼å¦æé¨ç½²å¤±è´¥ï¼èªå¨æ¢å¤å¤ä»½ç CSS
- ç»è®¡æ¥åï¼è¾åºæ´æ°ç»è®¡ï¼æå/è·³è¿/å¤±è´¥é¡¹ç®æ°éï¼
使ç¨ç¤ºä¾
æ¥éª¤ 1ï¼å夿æ°ç CSS
å¨ skill ç®å½ä¸ä¿®å¤ææ¹è¿ templates/minimal.cssï¼
cd /Users/joe/.claude/skills/knowledge-site-creator
# ç¼è¾ templates/minimal.css
# ä¿®å¤ bug ææ¹è¿æ ·å¼
æ¥éª¤ 2ï¼é¢è§å°æ´æ°ç项ç®
bash scripts/update-css.sh --dry-run
è¾åºç¤ºä¾ï¼
ð æ¼ç»æ¨¡å¼ï¼ä¸ä¼å®é
æ´æ°ï¼
ð CSS æºæä»¶ï¼/path/to/templates/minimal.css
ð æä»¶å¤§å°ï¼12345 bytes
ð æ«æ workshop 项ç®...
================================================
ð¦ 项ç®ï¼evolutionary-psychology-workshop
ð å°æ´æ°ï¼/path/to/evolutionary-psychology-workshop/css/minimal.css
ð å°éæ°é¨ç½²å° Vercel
================================================
ð¦ 项ç®ï¼word-root-workshop
â è·³è¿ï¼CSS å·²æ¯ææ°çæ¬
================================================
ð æ´æ°æ»ç»
â
æåæ´æ°ï¼1 个项ç®
â ï¸ è·³è¿ï¼1 个项ç®
ð¡ è¿æ¯æ¼ç»æ¨¡å¼ï¼æ²¡æå®é
æ§è¡ä»»ä½æä½
è¦å®é
æ§è¡ï¼è¯·è¿è¡ï¼bash scripts/update-css.sh
æ¥éª¤ 3ï¼æ§è¡æ¹éæ´æ°
bash scripts/update-css.sh
è¾åºç¤ºä¾ï¼
================================================
ð¦ 项ç®ï¼evolutionary-psychology-workshop
ð¾ å·²å¤ä»½æ§ CSSï¼/path/to/css/minimal.css.backup
â å·²æ´æ° CSS
ð éæ°é¨ç½²å° Vercel...
â
é¨ç½²æå
================================================
ð æ´æ°æ»ç»
â
æåæ´æ°ï¼1 个项ç®
â ï¸ è·³è¿ï¼1 个项ç®
å®å ¨ç¹æ§
- æºè½è·³è¿ï¼èªå¨è·³è¿å·²æ¯ææ°çæ¬ç项ç®ï¼é¿å ä¸å¿ è¦çé¨ç½²
- èªå¨å¤ä»½ï¼æ´æ°åå¤ä»½æ§ CSS 为
.backupæä»¶ - å¤±è´¥åæ»ï¼é¨ç½²å¤±è´¥æ¶èªå¨æ¢å¤å¤ä»½
- Git è®°å½ï¼æææ´æ°é½æ Git commitï¼å¯è¿½æº¯åå²
- æ¼ç»æ¨¡å¼ï¼
--dry-run模å¼è®©ä½ å çç伿´æ°ä»ä¹
注æäºé¡¹
â ï¸ æ´æ°åæ£æ¥ï¼
- ç¡®ä¿
templates/minimal.csså·²ç»è¿æµè¯ - 使ç¨
--dry-runå é¢è§å°æ´æ°çé¡¹ç® - æ£æ¥æ¯å¦æé¡¹ç®æ£å¨è¢«ç¨æ·è®¿é®ï¼é¿å é«å³°ææ´æ°ï¼
â ï¸ æ´æ°åéªè¯ï¼
- èæ¬å®æåï¼éæºæ½æ¥ 2-3 个项ç®çç½ç«
- ç¡®è®¤æ°æ ·å¼çæä¸æ²¡æç ´åå¸å±
- æ£æ¥ç§»å¨ç«¯æ¾ç¤ºæ¯å¦æ£å¸¸
â ï¸ å¤±è´¥å¤çï¼
- 妿æä¸ªé¡¹ç®é¨ç½²å¤±è´¥ï¼èæ¬ä¼èªå¨åæ»è¯¥é¡¹ç®ç CSS
- 失败ç项ç®ä¸å½±åå ¶ä»é¡¹ç®çæ´æ°
- å¯ä»¥æå¨è¿å
¥å¤±è´¥ç项ç®ç®å½ï¼ä½¿ç¨
vercel --prod --yeséè¯
æ©å±æ§
æªæ¥å¯æ©å±çæ´æ°ç±»åï¼
å½åèæ¬ä» æ¯æ CSS æ´æ°ï¼ä½åæ ·çæºå¶å¯ä»¥æ©å±å°ï¼
- JavaScript æä»¶æ´æ°ï¼
js/storage.jsçï¼ - HTML æ¨¡æ¿æ´æ°ï¼å¦ä¿®å¤ meta æ ç¾ç¼ºå¤±ï¼
- é
ç½®æä»¶æ´æ°ï¼
vercel.jsonçï¼ - æ¹éè¿ç§»ï¼å¦æ°æ®ç»æåæ´ï¼
æ©å±æ¹æ³ï¼åè update-css.sh åå»ºç±»ä¼¼èæ¬ï¼å¦ update-storage.shãupdate-meta-tags.sh çã