Skip to content

Commit 66a13eb

Browse files
committed
feat: update .gitignore and enhance documentation; add UI guidelines and fix service worker loader
1 parent 417f5ad commit 66a13eb

5 files changed

Lines changed: 108 additions & 20 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ dist/
44
*.zip
55
*.vsix
66
.memory/cleanup.log
7+
8+
*storybook.log
9+
storybook-static

.memory/decisions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,5 @@
5353
- [markdown-rendering] Messages in the dashboard render markdown via react-markdown + remark-gfm + @tailwindcss/typography. MarkdownContent component lives in src/components/MarkdownContent.tsx. Overflow is hard-capped: pre=overflow-x-auto, img=max-w-full, table wrapped in overflow-x-auto div, links=break-all.
5454

5555
- [message-copy-share] Per-message actions: Copy (MD/TXT toggle, shared copyMode state) + Share (Web Share API with clipboard fallback). Action bar is hover-revealed via Tailwind group/group-hover pattern. stripMarkdown utility lives in src/utils/stripMarkdown.ts (regex-only, no deps).
56+
57+
- [dark-mode] Dark mode uses class-based toggling (.dark on root div). @custom-variant dark in global.css. Semantic tokens (background, grid, muted, faint) override via .dark CSS block. bg-white/gray/text-black use explicit dark: variants. Preference stored in localStorage("theme"). Moon/Sun toggle in sidebar header.

.memory/quirks.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@
55
- [project-quirks] Project-specific weirdness — the non-obvious stuff.
66

77
- [claude-inject-fallback] Claude's `#chat-input-file-upload-onpage` is lazy-rendered — absent on existing chats until the composer is interacted with. Use MutationObserver to wait 2 s for it; fall back to ClipboardEvent paste into ProseMirror `div[contenteditable]` if still absent.
8+
9+
- [storybook10-blocks-import] In Storybook 10, import Meta/ColorPalette/ColorItem from "@storybook/addon-docs/blocks", NOT "@storybook/blocks". The "@storybook/blocks" package is v8-only and breaks Storybook 10.
10+
11+
- [storybook10-render-only-stories] In Storybook 10, render-only showcase stories must use `StoryObj` (no generic) not `StoryObj<typeof meta>`. Using the meta-typed Story for stories with a render function but no args causes TS2322 because Storybook 10 enforces required args.
12+
13+
- [vitest-crx-conflict] vitest browser runner hangs (30s timeout) if crx plugin is included via `extends: true`. Keep vitest config in a separate vitest.config.ts that only includes react + tailwindcss plugins, never crx.

docs/ui-guidelines.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# UI Guidelines & Design System
2+
3+
This document outlines the UI components, styling conventions, design tokens, and best practices for developing HackLM Migrate interfaces.
4+
5+
## 1. Design Tokens and Theming
6+
7+
We use **Tailwind CSS v4** for our styling foundation. Core tokens are stored as CSS variables in `src/styles/global.css`.
8+
9+
### Colors
10+
- **Background (`bg-background`)**: `#fbfbfb` (Light) / `#111111` (Dark)
11+
- **Accent (`text-accent`, `bg-accent`)**: `#fb631b` (Primary brand color) / Hover: `#e85310`
12+
- **Grid / Borders (`border-grid`)**: `#e2e2e2` (Light) / `#2a2a2a` (Dark)
13+
- **Text (`text-muted`, `text-faint`)**: `#666666`, `#999999` (Light) / `#888888`, `#555555` (Dark)
14+
15+
### Typography
16+
- **Sans-Serif (`font-sans`)**: `Inter`, default for all regular UI text.
17+
- **Monospace (`font-mono`)**: `JetBrains Mono`, used for code blocks, badges, and technical readouts.
18+
19+
### Sizing and Spacing
20+
- **Border Radius (`rounded-sm`)**: Default small radius is `4px` (`--radius-sm`).
21+
- **Icons**: Handled by `lucide-react`. Standard sizes used are usually `16px` for inline actions and `24px` for larger UI elements.
22+
23+
### Dark Mode
24+
Dark mode is class-based. It triggers when an ancestor has the `.dark` class (applied via `@custom-variant dark (&:where(.dark, .dark *));`).
25+
Semantic tokens (like `--color-background`) automatically flip when in dark mode, making it easy to support both modes without writing `dark:` utility classes everywhere.
26+
27+
---
28+
29+
## 2. Core Components
30+
31+
### `HacklmIcon` & `HacklmLogo`
32+
- **Location**: `src/components/HacklmIcon.tsx`
33+
- **Usage**: Use this for displaying the brand logo. It dynamically selects the best resolution (`16`, `48`, `128`) based on the requested `size` prop and resolves the path for extension contexts using `chrome.runtime.getURL`.
34+
- **Example**: `<HacklmLogo size={24} />`
35+
36+
### `MarkdownContent`
37+
- **Location**: `src/components/MarkdownContent.tsx`
38+
- **Usage**: Used to render extracted chat messages. Relies on `@tailwindcss/typography` (`prose`).
39+
- **Styling Details**:
40+
- Overrides standard `code` and `pre` tags to utilize `.bg-gray-100` and `font-mono`.
41+
- Enforces `break-all` on links to prevent layout overflows.
42+
- Horizontal scrolling enabled on tables and code blocks to keep chat bubbles contained.
43+
44+
### `FloatingDial`
45+
- **Location**: `src/content-scripts/FloatingDial.tsx`
46+
- **Usage**: The draggable primary Speed-Dial FAB injected into host pages.
47+
- **Styling Details**:
48+
- Because content scripts run in host pages (which might have conflicting CSS), `FloatingDial` leans heavily on **inline styles** for layout positioning and animations to guarantee isolation.
49+
- Features high `z-index` (`2147483646` / `2147483647`) to sit above all host content.
50+
51+
---
52+
53+
## 3. Styling Rules & Best Practices
54+
55+
1. **Host Page Isolation (Content Scripts)**:
56+
When building UI injected directly into host pages (like `FloatingDial`), prefer robust inline styles or completely reset shadow-DOM constraints. Relying purely on global Tailwind classes might lead to styles being overridden or bleeding into the host site's CSS.
57+
2. **Extension Pages (Popup / Options)**:
58+
For dedicated extension pages, use standard Tailwind utility classes enthusiastically.
59+
3. **Accessibility**:
60+
Use `lucide-react` icons with appropriate `aria-label` or `title` hints. Ensure interactive elements show visual changes on `hover`, `focus`, and `active` states (e.g., dial buttons have hover background tweaks).
61+
4. **Animations**:
62+
Keep micro-interactions fast and subtle. For example, the `FloatingDial` uses a `0.15s ease` transition for background changes and a staggered entrance animation for child actions.
63+
5. **No Placeholders**:
64+
Ensure content behaves well when empty. `FloatingDial`'s restore modal gracefully renders an "Empty Vault" state natively.
65+
66+
---
67+
68+
## 4. Component-Driven UI with Storybook
69+
70+
We use [Storybook](https://storybook.js.org/) to develop and test components in isolation. This is especially useful for components like `HacklmIcon` and `MarkdownContent` which can be verified outside the browser extension environment.
71+
72+
### Running Storybook
73+
To start the local Storybook server:
74+
75+
```bash
76+
npm run storybook
77+
```
78+
79+
This will spin up a local server (typically at `http://localhost:6006` or `http://localhost:6007`) where you can interact with the documented components, toggle dark mode, and verify Tailwind styling.
80+
81+
### Writing Stories
82+
When creating new reusable UI components in `src/components`, consider adding a `.stories.tsx` file alongside them. See `src/components/HacklmIcon.stories.tsx` or `src/components/MarkdownContent.stories.tsx` for examples.

vite.config.ts

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import path from "node:path";
1212
* This plugin rewrites the file after bundling to import the actual
1313
* built background chunk.
1414
*/
15+
1516
function fixServiceWorkerLoader(): Plugin {
1617
return {
1718
name: "fix-service-worker-loader",
@@ -21,49 +22,43 @@ function fixServiceWorkerLoader(): Plugin {
2122
const outDir = path.resolve(__dirname, "dist");
2223
const loaderPath = path.join(outDir, "service-worker-loader.js");
2324
const assetsDir = path.join(outDir, "assets");
24-
2525
if (!fs.existsSync(loaderPath) || !fs.existsSync(assetsDir)) return;
2626

2727
// CRXJS names the background bundle after its entry: index.ts-<hash>.js
28-
const bgBundle = fs
29-
.readdirSync(assetsDir)
30-
.find((f) => /^index\.ts-.*\.js$/.test(f));
31-
28+
const bgBundle = fs.readdirSync(assetsDir).find(f => /^index\.ts-.*\.js$/.test(f));
3229
if (!bgBundle) {
3330
console.warn("[fix-service-worker-loader] background bundle not found");
3431
return;
3532
}
36-
3733
fs.writeFileSync(loaderPath, `import './assets/${bgBundle}';\n`);
38-
console.log(
39-
`[fix-service-worker-loader] rewrote loader → assets/${bgBundle}`
40-
);
41-
},
34+
console.log(`[fix-service-worker-loader] rewrote loader → assets/${bgBundle}`);
35+
}
4236
};
4337
}
44-
4538
export default defineConfig({
46-
plugins: [react(), tailwindcss(), crx({ manifest }), fixServiceWorkerLoader()],
39+
plugins: [react(), tailwindcss(), crx({
40+
manifest
41+
}), fixServiceWorkerLoader()],
4742
server: {
4843
/* Allow the Chrome extension's service worker (chrome-extension://<id>)
4944
* to fetch @vite/env, HMR scripts, and other dev-server resources.
5045
* Without this, service worker registration fails in dev mode with
5146
* "Status code: 3" and a CORS error. */
5247
cors: {
5348
origin: ["chrome-extension://*", /^chrome-extension:\/\//],
54-
methods: ["GET", "HEAD"],
49+
methods: ["GET", "HEAD"]
5550
},
5651
headers: {
57-
"Access-Control-Allow-Origin": "*",
58-
},
52+
"Access-Control-Allow-Origin": "*"
53+
}
5954
},
6055
build: {
6156
outDir: "dist",
6257
rollupOptions: {
6358
input: {
6459
options: "src/options/index.html",
65-
popup: "src/popup/index.html",
66-
},
67-
},
68-
},
69-
});
60+
popup: "src/popup/index.html"
61+
}
62+
}
63+
}
64+
});

0 commit comments

Comments
 (0)