diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f432071..61bafa3 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -51,6 +51,11 @@ "name": "velog-cli", "source": "./plugins/velog-cli", "description": "Manage velog.io blog posts from the terminal — create, edit, publish, and browse posts via the velog CLI" + }, + { + "name": "hamsurang-slide", + "source": "./plugins/hamsurang-slide", + "description": "Hamsurang brand HTML presentation generator. Soft Modern design with light/dark themes, 14 slide types, 4-color code highlighting." } ] } diff --git a/README.ko.md b/README.ko.md index a307724..61cca5e 100644 --- a/README.ko.md +++ b/README.ko.md @@ -86,6 +86,7 @@ bash scripts/scaffold-plugin.sh | [library-analyzer](./plugins/library-analyzer) | 병렬 에이전트를 활용하여 오픈소스 라이브러리의 기여 준비도를 분석하는 스킬 | [minsoo.web](https://github.com/minsoo-web) | | [obsidian-brain](./plugins/obsidian-brain) | Claude Code 세션의 학습 내용을 Obsidian 볼트에 제텔카스텐 노트로 아카이빙하고 볼트 지식을 대화 컨텍스트로 활용하는 스킬 | [minsoo.web](https://github.com/minsoo-web) | | [velog-cli](./plugins/velog-cli) | 터미널에서 velog.io 블로그 포스트를 관리 — velog CLI로 글 작성, 수정, 퍼블리시, 트렌딩 조회 | [minsoo.web](https://github.com/minsoo-web) | +| [hamsurang-slide](./plugins/hamsurang-slide) | 함수랑 브랜드 HTML 프레젠테이션 생성기. Soft Modern 디자인, 라이트/다크 테마, 14가지 슬라이드 타입, 4색 코드 하이라이팅 | [Sonny](https://github.com/sonsurim) | *플러그인을 기여하고 싶으신가요? [기여 방법](docs/contributors/contributing.md)을 확인하세요.* diff --git a/README.md b/README.md index 3c6ee41..1123e62 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ bash scripts/scaffold-plugin.sh | [library-analyzer](./plugins/library-analyzer) | Analyze open-source libraries for contribution readiness with parallel agents | [minsoo.web](https://github.com/minsoo-web) | | [obsidian-brain](./plugins/obsidian-brain) | Archive learnings from Claude Code sessions to Obsidian vault as Zettelkasten notes and use vault knowledge as conversational context | [minsoo.web](https://github.com/minsoo-web) | | [velog-cli](./plugins/velog-cli) | Manage velog.io blog posts from the terminal — create, edit, publish, and browse posts via the velog CLI | [minsoo.web](https://github.com/minsoo-web) | +| [hamsurang-slide](./plugins/hamsurang-slide) | Hamsurang brand HTML presentation generator. Soft Modern design with light/dark themes, 14 slide types, 4-color code highlighting. | [Sonny](https://github.com/sonsurim) | *Have a plugin to share? See [Contributing](docs/contributors/contributing.md).* diff --git a/plugins/hamsurang-slide/.claude-plugin/plugin.json b/plugins/hamsurang-slide/.claude-plugin/plugin.json new file mode 100644 index 0000000..f86d26b --- /dev/null +++ b/plugins/hamsurang-slide/.claude-plugin/plugin.json @@ -0,0 +1,12 @@ +{ + "name": "hamsurang-slide", + "version": "1.0.0", + "description": "Hamsurang brand HTML presentation generator. Soft Modern design with light/dark themes, 14 slide types, 4-color code highlighting.", + "author": { + "name": "Sonny", + "github": "sonsurim" + }, + "license": "MIT", + "keywords": ["hamsurang", "slide", "presentation", "soft-modern", "PPT"], + "skills": "./skills/" +} diff --git a/plugins/hamsurang-slide/README.md b/plugins/hamsurang-slide/README.md new file mode 100644 index 0000000..f0e94cd --- /dev/null +++ b/plugins/hamsurang-slide/README.md @@ -0,0 +1,65 @@ +# hamsurang-slide + +> Brand presentation generator for Hamsurang (함수랑산악회) with Soft Modern design. + +## Features + +- **Soft Modern** design — glassmorphism cards, green-tinted gradients, soft shadows +- **Light / Dark themes** — green-tinted dark mode included +- **14 slide types** — Title, Agenda, Section Divider, Key Point, Quote, Comparison, Flow, Card Grid, Content, Code, Architecture, Timetable, Timeline, Closing +- **4-color code highlighting** — custom highlight.js theme +- **mermaid.js diagrams** support +- **Speaker notes** — `S` key opens popup window +- **Single HTML file** output — opens directly in browser + +## Installation + +```bash +claude plugin install hamsurang-slide@hamsurang/kit +``` + +Or copy `plugins/hamsurang-slide/` into your project. Pi auto-detects `.claude-plugin/plugin.json`. + +## Trigger Phrases + +- `hamsurang 발표` / `hamsurang PPT` / `hamsurang slide` +- `함수랑 발표` / `함수랑 슬라이드` / `함수랑 PPT` + +## Workflow + +1. Analyze input (topic, duration, audience) +2. Generate outline → user confirmation +3. Select theme → user confirmation +4. Generate HTML (sequential reference loading) +5. Write speaker notes +6. Inline SVG assets → save file + +## File Structure + +``` +plugins/hamsurang-slide/ +├── .claude-plugin/plugin.json +├── README.md +└── skills/hamsurang-slide/ + ├── SKILL.md + ├── references/ + │ ├── generation-rules.md (CSS SSOT — all design values) + │ ├── design-system.md (philosophy, component patterns) + │ ├── slide-catalog.md (14 slide type HTML structures) + │ ├── html-spec.md (HTML structure, JS, CDN) + │ └── images/ (SVG brand assets) + └── scripts/ + └── inline_assets.mjs +``` + +### SSOT Principle + +**`generation-rules.md`** is the single source of truth for all CSS values (colors, typography, spacing, radii, shadows). Other reference files describe _patterns and structure_ but never hardcode style values — they reference CSS variables defined in generation-rules.md. + +## Requirements + +- Node.js + +## License + +MIT diff --git a/plugins/hamsurang-slide/skills/hamsurang-slide/SKILL.md b/plugins/hamsurang-slide/skills/hamsurang-slide/SKILL.md new file mode 100644 index 0000000..504ee9c --- /dev/null +++ b/plugins/hamsurang-slide/skills/hamsurang-slide/SKILL.md @@ -0,0 +1,146 @@ +--- +name: hamsurang-slide +description: "Use when the user mentions 'hamsurang presentation', 'hamsurang PPT', 'hamsurang slide', '함수랑 발표', '함수랑 슬라이드', '함수랑 PPT', 'hamsurang 발표', or any presentation request in a Hamsurang (함수랑산악회) context — even if they don't explicitly say 'slide'." +--- + +# hamsurang-slide — Hamsurang HTML Presentation Generator + +## Overview + +Generates single-file HTML presentations with Hamsurang brand Soft Modern design. +Light/dark themes, 14 slide types, 4-color code highlighting, glassmorphism cards. +Output is always a single `.html` file — opens directly in a browser. + +## When to Use + +Activate when the request matches any of: +- "hamsurang 발표", "hamsurang PPT", "hamsurang slide" +- "함수랑 발표", "함수랑 슬라이드", "함수랑 PPT" +- Any mention of "presentation", "slide", or "PPT" in a Hamsurang context + +## Workflow + +### Step 1: Analyze Input + +Extract from the user's request: +- Topic +- Duration (→ slide count mapping) +- Audience +- Language (generate content in the user's conversation language) + +Default duration is 10 minutes. + +| Duration | Slide Count | +|----------|-------------| +| 5 min | 8–12 | +| 10 min | 12–18 (default) | +| 15 min | 18–25 | +| 20 min | 25–30 | +| 30 min | 30–40 | + +### Step 2: Generate Outline & Confirm + +**Get user confirmation before proceeding.** + +Present as a table: + +| # | Type | Title | Key Points | +|---|------|-------|------------| +| 1 | Title | ... | ... | +| 2 | Agenda | ... | ... | +| ... | ... | ... | ... | +| N | Closing | ... | ... | + +Incorporate edits and re-confirm if requested. + +### Step 3: Choose Theme & Confirm + +> **Choose a theme:** +> - **Light** — bright background, informative and open +> - **Dark** — green-tinted dark background, immersive + +Default: Light. + +### Step 4: Generate HTML + +**Reference loading order (read in this exact order):** + +1. `references/generation-rules.md` — **CSS single source of truth.** Copy all CSS from §1–14 into ` + + +
+
+
+ +
+
1 / N
+
+ + + +``` + +For dark theme, change to `data-theme="dark"`. + +## 4. Navigation JS + +Complete JavaScript code to copy: + +```javascript +(function() { + const slides = document.querySelectorAll('.slide'); + const progressBar = document.querySelector('.progress-bar'); + const currentEl = document.querySelector('.slide-counter .current'); + const totalEl = document.querySelector('.slide-counter .total'); + let currentIndex = 0; + let notesWindow = null; + + totalEl.textContent = slides.length; + + function goTo(index) { + if (index < 0 || index >= slides.length) return; + slides[currentIndex].classList.remove('active'); + currentIndex = index; + slides[currentIndex].classList.add('active'); + currentEl.textContent = currentIndex + 1; + progressBar.style.width = ((currentIndex + 1) / slides.length * 100) + '%'; + updateNotes(); + } + + function updateNotes() { + if (notesWindow && !notesWindow.closed) { + const notes = slides[currentIndex].getAttribute('data-notes') || ''; + notesWindow.document.body.innerHTML = + '
' + + '

Slide ' + (currentIndex + 1) + ' / ' + slides.length + '

' + + '

' + notes + '

'; + } + } + + document.addEventListener('keydown', function(e) { + switch(e.key) { + case 'ArrowRight': case ' ': + e.preventDefault(); goTo(currentIndex + 1); break; + case 'ArrowLeft': + e.preventDefault(); goTo(currentIndex - 1); break; + case 'f': case 'F': + if (!document.fullscreenElement) { document.documentElement.requestFullscreen(); } + else { document.exitFullscreen(); } + break; + case 's': case 'S': + if (!notesWindow || notesWindow.closed) { + notesWindow = window.open('', 'notes', 'width=600,height=400'); + notesWindow.document.title = 'Speaker Notes'; + } + updateNotes(); + break; + case 'Escape': + if (document.fullscreenElement) { document.exitFullscreen(); } + break; + } + }); + + function resize() { + const container = document.querySelector('.slides-container'); + const scaleX = window.innerWidth / 1280; + const scaleY = window.innerHeight / 720; + const scale = Math.min(scaleX, scaleY); + container.style.transform = 'scale(' + scale + ')'; + } + + window.addEventListener('resize', resize); + resize(); + goTo(0); +})(); +``` + +**Keyboard mapping:** + +| Key | Action | +|-----|--------| +| `→` / `Space` | Next slide | +| `←` | Previous slide | +| `F` | Toggle fullscreen | +| `S` | Speaker notes popup | +| `Escape` | Exit fullscreen | + +## 5. highlight.js Integration + +Append to script: + +```javascript +if (typeof hljs !== 'undefined') { hljs.highlightAll(); } +``` + +Do not include highlight.js CSS — generation-rules.md §10 custom override replaces it. + +## 6. mermaid.js Integration + +Append to script: + +```javascript +if (typeof mermaid !== 'undefined') { + const theme = document.documentElement.getAttribute('data-theme'); + mermaid.initialize({ + startOnLoad: false, + theme: theme === 'dark' ? 'dark' : 'default', + securityLevel: 'loose', + themeVariables: theme === 'dark' ? { + primaryColor: '#1a3a2e', + primaryTextColor: '#e0e0e0', + primaryBorderColor: '#2bca9b', + lineColor: '#2bca9b', + secondaryColor: '#1e2d28', + tertiaryColor: '#162420', + nodeBorder: '#2bca9b', + mainBkg: '#1a3a2e', + nodeTextColor: '#e0e0e0', + edgeLabelBackground: '#0c1410' + } : {} + }); + + async function renderMermaid() { + const elements = document.querySelectorAll('.mermaid'); + for (let i = 0; i < elements.length; i++) { + const el = elements[i]; + const code = el.textContent; + try { + const { svg } = await mermaid.render('mermaid-' + i, code); + el.innerHTML = svg; + } catch (err) { + el.innerHTML = '
' + code + '
'; + } + } + } + + renderMermaid(); +} +``` + +## 7. Print / PDF + +Print rules are defined in generation-rules.md §11. + +Browser print (`Ctrl+P`) for PDF export: +- Hides controls, progress bar, counter +- Reflows all slides to visible +- Page-break per slide +- 1280×720 landscape page size + +## 8. Accessibility + +- All images require `alt` text +- Decorative SVGs get `aria-hidden="true"` +- All navigation is keyboard-accessible +- Use semantic HTML elements (h1, h2, h3, p, ul, ol, table, blockquote) +- Color contrast: WCAG AA (body 4.5:1, large text 3:1) +- `lang="ko"` attribute required diff --git a/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/logo-white.svg b/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/logo-white.svg new file mode 100644 index 0000000..4ffafd6 --- /dev/null +++ b/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/logo-white.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/logo.svg b/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/logo.svg new file mode 100644 index 0000000..e344a7a --- /dev/null +++ b/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/logo.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/mountain-white.svg b/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/mountain-white.svg new file mode 100644 index 0000000..58c461e --- /dev/null +++ b/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/mountain-white.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/mountain.svg b/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/mountain.svg new file mode 100644 index 0000000..9200679 --- /dev/null +++ b/plugins/hamsurang-slide/skills/hamsurang-slide/references/images/mountain.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/plugins/hamsurang-slide/skills/hamsurang-slide/references/slide-catalog.md b/plugins/hamsurang-slide/skills/hamsurang-slide/references/slide-catalog.md new file mode 100644 index 0000000..b89c026 --- /dev/null +++ b/plugins/hamsurang-slide/skills/hamsurang-slide/references/slide-catalog.md @@ -0,0 +1,236 @@ +# Slide Catalog + +14 slide types. The agent writes HTML/CSS directly for each type. +Copy all CSS from `generation-rules.md` into `