Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
28367b4
docs: add component inventory for design system gap analysis
singyichen Mar 31, 2026
d4e6ce9
docs: add P1 component specs to design system MASTER.md
singyichen Mar 31, 2026
a827fa2
docs: add P2 component specs to design system MASTER.md
singyichen Mar 31, 2026
1f0ffff
docs: add P3 component specs to design system (Avatar, Tooltip, Mobil…
singyichen Mar 31, 2026
384ae22
docs: add P4 component specs to design system (Divider, List)
singyichen Mar 31, 2026
fbf92f2
docs: enforce English-only rule for design/system/MASTER.md
singyichen Mar 31, 2026
fc2feb9
docs: translate MASTER.md to English only
singyichen Apr 1, 2026
e38c4bc
chore: update design-system.pen wireframe
singyichen Apr 1, 2026
5a0491c
docs: update inventory.md to reflect completed component definitions
singyichen Apr 1, 2026
87c9557
fix: resolve navbar height inconsistency and remove full-width colon …
singyichen Apr 1, 2026
45fc907
fix: move Toast to fixed bottom-right position per design system spec
singyichen Apr 1, 2026
06e0e7e
fix: correct md: breakpoint value in Mobile Bottom Tab Bar spec (640p…
singyichen Apr 1, 2026
df39e1c
docs: add functional map (Mermaid + XMind source)
singyichen Apr 1, 2026
75e2150
chore: remove XMind binary from repo
singyichen Apr 1, 2026
81c6939
docs: move functional-map.md to docs/diagrams/
singyichen Apr 1, 2026
bfcca71
docs: move functional-map.md into dedicated folder
singyichen Apr 1, 2026
142b860
docs: add xmind-import skill, update IA and functional map
singyichen Apr 1, 2026
8aab208
chore: add .qodo/ to .gitignore
singyichen Apr 1, 2026
abd1520
docs: remove version suffix from IA document title
singyichen Apr 1, 2026
527b8fc
fix: address PR #17 review findings
singyichen Apr 1, 2026
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
16 changes: 13 additions & 3 deletions .claude/SKILLS.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ This document provides a comprehensive overview of all available Spec-Kit Comman
│ │ ├── defect-report/
│ │ ├── traceability-matrix/
│ │ └── test-report/
│ ├── xmind-import/ # Fetch XMind share URL → Mermaid
│ ├── adamelliotfields-skills-d2-diagram/ # Diagramming
│ └── ui-ux-pro-max/ # UI/UX Design Intelligence
├── agents/ # AI Agent definitions (35 agents)
Expand Down Expand Up @@ -127,6 +128,15 @@ Skills for designing APIs, services, data models, and architecture.
| `/flowchart` | Generate Mermaid flowcharts | `/flowchart annotation submission and async scoring flow` |
| `/d2-diagram` | Generate D2 diagrams (architecture, flow, thesis chapter) | `/d2-diagram system architecture` |

### Diagramming (2 skills)

Skills for importing and generating diagrams from external sources.

| Skill | Purpose | Example Usage |
|-------|---------|---------------|
| `/d2-diagram` | Generate D2 diagrams (architecture, flow, thesis chapter) | `/d2-diagram system architecture` |
| `/xmind-import` | Fetch XMind share URL → parse JSON → output Mermaid `flowchart LR` | `/xmind-import https://app.xmind.com/share/PKjJEIHD docs/functional-map/functional-map.md` |

### UI/UX Design (1 skill)

Skills for UI design systems, component styling, and UX best practices.
Expand Down Expand Up @@ -196,8 +206,8 @@ Skills for quality gates, defect management, traceability, and reporting.
| Test Engineering | 6 | test-plan, test-coverage, test-data-strategy, test-tracking, exploratory-testing, regression-suite |
| Quality Assurance | 4 | quality-gate, defect-report, traceability-matrix, test-report |
| UI/UX Design | 1 | ui-ux-pro-max |
| Diagramming | 1 | d2-diagram (adamelliotfields) |
| **Total** | **30** | |
| Diagramming | 2 | d2-diagram (adamelliotfields), xmind-import |
| **Total** | **31** | |

---

Expand Down Expand Up @@ -245,4 +255,4 @@ For the Label Suite project, these skills enforce additional constraints for the
---

*Last Updated: 2026-03-25*
*Total Skills: 30 | Spec-Kit Commands: 9*
*Total Skills: 31 | Spec-Kit Commands: 9*
142 changes: 142 additions & 0 deletions .claude/skills/xmind-import/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
---
name: xmind-import
description: Use this skill whenever the user shares an XMind share URL (app.xmind.com/share/...) and wants to import, convert, or export the mind map — even if they don't say "xmind-import" explicitly. Triggers on: "convert this XMind link", "import my mind map", "turn this XMind into Mermaid", "parse this XMind", or when the user pastes an app.xmind.com/share URL alongside any request involving diagrams or markdown. Fetches the mind map JSON via Playwright MCP, converts the tree structure to a Mermaid flowchart LR diagram, and writes it to a markdown file or prints it to the conversation.
---

# XMind Import

Fetch a public XMind share link, extract the mind map JSON, and convert it to a `flowchart LR` Mermaid diagram.

## Usage

```
/xmind-import <xmind-share-url> [output-path]
```

**Examples:**

```
/xmind-import https://app.xmind.com/share/PKjJEIHD docs/functional-map/functional-map.md
/xmind-import https://app.xmind.com/share/ABC123
```

If `output-path` is omitted, print the Mermaid source to the conversation.

---

## Steps

### Step 1 — Extract the file ID from the URL

Parse the share URL to get `fileId`:

```
https://app.xmind.com/share/{fileId}
↑ this part
```

For example, `https://app.xmind.com/share/PKjJEIHD` → `fileId = PKjJEIHD`.

### Step 2 — Navigate with Playwright

Use `mcp__plugin_playwright_playwright__browser_navigate` to open the share page. This establishes the session cookies that allow the API call in Step 3 to succeed without authentication.

```
url: https://app.xmind.com/share/{fileId} ← substitute real fileId
```

### Step 3 — Wait for the SPA to load

Use `mcp__plugin_playwright_playwright__browser_wait_for` with `time: 3`.

The page title changes from the generic XMind branding to the mind map name (e.g., "Label Suite - Xmind AI") once the JavaScript has fully loaded.

### Step 4 — Fetch, parse, and convert in one browser call

Use `mcp__plugin_playwright_playwright__browser_evaluate` to fetch the XMind content API, walk the topic tree, and produce Mermaid output — all in a single call. Substitute the actual `fileId` into the fetch URL string before running.

```js
async () => {
const FILE_ID = 'PKjJEIHD'; // ← replace with actual fileId

const res = await fetch(`/api/drive/share/${FILE_ID}/content`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({})
});

if (!res.ok) return `ERROR: API returned ${res.status}`;

const data = await res.json();
const sheet = data[0];
const mapTitle = sheet.title ?? 'Mind Map';
const root = sheet.rootTopic;

const lines = ['flowchart LR'];
let counter = 0;

function sanitize(title) {
return (title ?? '').replace(/"/g, "'").replace(/\n/g, ' ').trim();
}

function walk(topic, parentId) {
const id = 'n' + counter++;
const label = sanitize(topic.title);
if (parentId === null) {
lines.push(` ${id}(["${label}"])`);
} else {
lines.push(` ${parentId} --> ${id}["${label}"]`);
}
if (topic.children?.attached) {
for (const child of topic.children.attached) {
walk(child, id);
}
}
}

walk(root, null);
return JSON.stringify({ title: mapTitle, mermaid: lines.join('\n') });
}
```

The function returns a JSON string with two fields:
- `title` — the mind map name (use this as the markdown heading)
- `mermaid` — the full `flowchart LR` source

### Step 5 — Write or print output

Parse the JSON string returned by Step 4, then:

**If an output path was given**, write a markdown file using the `Write` tool with this structure:

```
# {title from Step 4}

```mermaid
{mermaid from Step 4}
` ``
```

*(Note: close the fence with three backticks — the above uses a space before the last ` `` ` only to avoid nesting issues in this document.)*

**If no output path was given**, print the mermaid source in the conversation inside a `mermaid` code fence.

---

## Error Handling

| Situation | Action |
|-----------|--------|
| API returns non-200 (e.g., 401, 403) | The map is private or requires login. Inform the user — public share links work without auth, private ones do not. |
| `rootTopic` is missing | The XMind API format may have changed. Print the raw API response so the user can inspect it. |
| Playwright tools unavailable | Inform the user that this skill requires the Playwright MCP plugin to be installed. `WebFetch` cannot load XMind's SPA content. |
| `title` field missing in response | Fall back to the browser page title (available via `browser_evaluate`: `() => document.title`). |

---

## Notes

- **Auth**: Public share links work without login. The browser session cookie from Step 2 is what grants access to the content API.
- **Layout**: `flowchart LR` is a horizontal left-to-right tree. XMind's balanced layout (branches on both sides) cannot be reproduced in Mermaid — all branches appear on the right.
- **Folded nodes**: XMind `"branch": "folded"` is purely visual. All children are present in the JSON and will appear in the output.
- **`fileId` substitution**: Always replace the `FILE_ID` constant in the evaluate script with the actual ID from the URL before running — do not leave it as `'PKjJEIHD'` which is the example from this skill's documentation.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ htmlcov/
# Generated assets (PNG files generated from SVG)
assets/logo/*.png
!assets/logo/social-preview.png

# Playwright MCP working directory (browser snapshots, console logs, temp files)
.playwright-mcp/

# Qodo code review bot working directory
.qodo/
3 changes: 2 additions & 1 deletion .specify/memory/constitution.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ Evaluation results must be fair and reproducible.

### VI. English-First
- Code, comments, docstrings, commit messages, and variable/function names are always written in English
- Traditional Chinese is permitted in `docs/`, `specs/`, `design/prototype/`, and `design/wireframes/` directories to accelerate research documentation and UI iteration
- Traditional Chinese is permitted in `docs/`, `specs/`, `design/prototype/`, `design/wireframes/`, and `design/system/inventory.md` to accelerate research documentation and UI iteration
- `design/system/MASTER.md` must be written in English only — it is consumed by AI agents and requires accurate token parsing
Comment on lines +50 to +51
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Constitution amended without version bump or date update, violating its own governance rules

Lines 50–51 add new rules to Principle VI (English-First): design/system/inventory.md is now Chinese-allowed and design/system/MASTER.md must be English-only. However, the version at .specify/memory/constitution.md:71 still reads 1.2.3 | Last Amended: 2026-03-30. The constitution's own Amendment Procedure (.specify/memory/constitution.md:58-62) requires bumping the version (this is at least a PATCH → 1.2.4) and using commit message format docs: amend constitution to vX.Y.Z ([reason]). Neither was done.

Prompt for agents
In .specify/memory/constitution.md, update line 71 from:
  **Version**: 1.2.3 | **Ratified**: 2026-03-18 | **Last Amended**: 2026-03-30
to:
  **Version**: 1.2.4 | **Ratified**: 2026-03-18 | **Last Amended**: 2026-04-01

Then amend the commit message for the constitution change to follow the required format:
  docs: amend constitution to v1.2.4 (add inventory.md Chinese exception and MASTER.md English-only rule)
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

- The only fully Chinese file outside those directories is `README.zh-TW.md`

## Governance
Expand Down
2 changes: 1 addition & 1 deletion .specify/templates/agent-file-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Auto-generated from feature plans. Last updated: [DATE]
- **KISS & YAGNI**: Pursue extreme simplicity. Reject over-engineering; write code only for current, clearly defined needs.
- **Config-Driven**: Task types and evaluation metrics are defined in YAML/JSON config — never hardcoded.
- **Security First (NON-NEGOTIABLE)**: Test-set answers must never be exposed to annotators or included in any annotator-facing API response.
- **English-First**: Code, comments, and commit messages are written in English. Traditional Chinese is permitted in `docs/`, `specs/`, `design/prototype/`, and `design/wireframes/`.
- **English-First**: Code, comments, and commit messages are written in English. Traditional Chinese is permitted in `docs/`, `specs/`, `design/prototype/`, `design/wireframes/`, and `design/system/inventory.md`. `design/system/MASTER.md` must be English only.

## Protected Files

Expand Down
2 changes: 1 addition & 1 deletion .specify/templates/plan-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
- [ ] III. Data Fairness: Does this involve test sets? If so, leakage prevention is planned
- [ ] IV. Test-First: Test plan is listed
- [ ] V. Simplicity: Any signs of over-engineering?
- [ ] VI. English-First: Code, comments, and commit messages in English; Traditional Chinese allowed in `docs/`, `specs/`, `design/prototype/`, and `design/wireframes/`
- [ ] VI. English-First: Code, comments, and commit messages in English; Traditional Chinese allowed in `docs/`, `specs/`, `design/prototype/`, `design/wireframes/`, and `design/system/inventory.md`; `design/system/MASTER.md` must be English only

## Project Structure

Expand Down
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ label-suite/
- `specs/` — all SDD spec files (`spec.md`, `plan.md`, `tasks.md`, `checklists/`)
- `design/prototype/` — HTML/CSS UI prototypes demonstrating bilingual (zh-TW/en) features
- `design/wireframes/` — Pencil wireframe files (`.pen`) demonstrating bilingual (zh-TW/en) UI designs
- `design/system/inventory.md` — component inventory tracking document
- **English only** (exceptions within otherwise Chinese-allowed directories):
- `design/system/MASTER.md` — consumed by AI agents (`ui-ux-pro-max`, Claude Code); must be in English for accurate token parsing
- `README.zh-TW.md` is maintained in Traditional Chinese for Chinese-speaking users.
- All conversations with Claude should be responded to in Traditional Chinese.

Expand Down
44 changes: 24 additions & 20 deletions design/prototype/pages/profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@

<!-- ── Top Navbar ── -->
<!-- Desktop: px-20 (80px) | Mobile: px-4 (16px) — from wireframe -->
<header class="h-14 bg-white border-b border-slate-200 flex items-center px-4 md:px-20 shrink-0 z-[200]" role="banner">
<header class="h-16 bg-white border-b border-slate-200 flex items-center px-4 md:px-20 shrink-0 z-[200]" role="banner">
<div class="flex items-center gap-3 flex-1">
<a href="dashboard.html" class="flex items-center gap-2.5 group focus:outline-none" aria-label="Label Suite — 回首頁">
<div class="w-8 h-8 bg-primary rounded-lg flex items-center justify-center group-hover:bg-secondary transition-colors duration-200">
Expand Down Expand Up @@ -142,20 +142,6 @@ <h2 class="text-xl md:text-2xl font-bold text-ink" data-i18n="page-title">個人
<p class="text-sm text-slate-500 mt-1 leading-relaxed" data-i18n="page-desc">管理您的帳號資訊與顯示偏好。</p>
</div>

<!-- ── Toast (hidden by default) ── -->
<div id="toast" role="status" aria-live="polite"
class="hidden mb-5 flex items-center gap-2 text-sm rounded-lg px-4 py-3 border">
<svg id="toast-icon" class="w-4 h-4 shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"></svg>
<span id="toast-text" class="flex-1"></span>
<button type="button" onclick="document.getElementById('toast').classList.add('hidden')"
class="ml-2 shrink-0 opacity-60 hover:opacity-100 cursor-pointer transition-opacity duration-150 focus:outline-none focus:ring-2 focus:ring-current rounded"
aria-label="關閉通知" data-i18n-aria-label="aria-toast-close">
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</div>

<!-- ── Profile Card ── -->
<!-- Desktop: p-8 rounded-2xl (padding 32, radius 16) | Mobile: p-4 rounded-xl (padding 16, radius 12) -->
<div class="bg-white border border-slate-200 rounded-xl md:rounded-2xl p-4 md:p-8 flex flex-col gap-5 md:gap-6">
Expand Down Expand Up @@ -322,6 +308,23 @@ <h2 class="text-xl md:text-2xl font-bold text-ink" data-i18n="page-title">個人
</nav>


<!-- ── Toast — fixed bottom-right (per design system spec) ── -->
<div id="toast"
class="hidden fixed bottom-6 right-6 z-[400] max-w-sm w-full"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Toast container overflows left viewport edge on mobile due to w-full combined with right-6

The toast container uses class="fixed bottom-6 right-6 z-[400] max-w-sm w-full". On mobile viewports, w-full resolves to 100% of the viewport width (e.g. 390px on iPhone 14), capped at 384px by max-w-sm. With right: 24px, the left edge computes to 390 - 24 - 384 = -18px, causing 18px of the toast (left padding + partial icon) to be clipped by the viewport. On a 375px viewport (listed in the MASTER.md pre-delivery checklist at design/system/MASTER.md:993), the overflow increases to 24px. The same classes appear in the MASTER.md Toast spec at design/system/MASTER.md:386, so the implementation faithfully follows a flawed spec.

Fix options

Remove w-full so the toast sizes to its content up to max-w-sm, or replace right-6 with responsive margin classes like mx-6 md:ml-auto md:mr-6.

Prompt for agents
Fix the toast container mobile overflow in two files:

1. design/prototype/pages/profile.html line 313: Change the toast outer div classes from
   class="hidden fixed bottom-6 right-6 z-[400] max-w-sm w-full"
   to remove w-full so the toast sizes to its content. Alternatively, use
   class="hidden fixed bottom-6 left-6 right-6 z-[400] max-w-sm ml-auto"
   which constrains from both sides and pushes the toast to the right via ml-auto.

2. design/system/MASTER.md line 386: Update the Toast spec HTML example to use the same corrected classes, so future pages built from the spec don't reproduce the bug.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

aria-live="polite" aria-atomic="true">
<div id="toast-inner" class="flex items-center gap-2 text-sm rounded-lg px-4 py-3 border shadow-md">
<svg id="toast-icon" class="w-4 h-4 shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"></svg>
<span id="toast-text" class="flex-1"></span>
<button type="button" onclick="document.getElementById('toast').classList.add('hidden')"
class="ml-2 shrink-0 opacity-60 hover:opacity-100 cursor-pointer transition-opacity duration-150 focus:outline-none focus:ring-2 focus:ring-current rounded"
aria-label="關閉通知" data-i18n-aria-label="aria-toast-close">
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
</div>
</div>

<!-- ── i18n + Logic ── -->
<script>
const STRINGS = {
Expand Down Expand Up @@ -533,19 +536,20 @@ <h2 class="text-xl md:text-2xl font-bold text-ink" data-i18n="page-title">個人
}

function showToast(type) {
const toast = document.getElementById('toast');
const toast = document.getElementById('toast');
const inner = document.getElementById('toast-inner');
const toastTxt = document.getElementById('toast-text');
const toastIcon = document.getElementById('toast-icon');
const s = STRINGS[currentLang];

toast.classList.remove('hidden', 'bg-green-50', 'border-green-200', 'text-green-700',
'bg-red-50', 'border-red-200', 'text-red-700');
inner.classList.remove('bg-green-50', 'border-green-200', 'text-green-700',
'bg-red-50', 'border-red-200', 'text-red-700');
if (type === 'success') {
toast.classList.add('bg-green-50', 'border-green-200', 'text-green-700');
inner.classList.add('bg-green-50', 'border-green-200', 'text-green-700');
toastTxt.textContent = s['toast-success'];
toastIcon.innerHTML = `<polyline points="20 6 9 17 4 12"/>`;
} else {
toast.classList.add('bg-red-50', 'border-red-200', 'text-red-700');
inner.classList.add('bg-red-50', 'border-red-200', 'text-red-700');
toastTxt.textContent = s['toast-error'];
toastIcon.innerHTML = `<circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>`;
}
Expand Down
Loading
Loading