Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"presets": [
["@babel/preset-env", { "targets": { "node": "current" } }],
"@babel/preset-typescript"
]
}
38 changes: 38 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["react", "@typescript-eslint"],
rules: {
"react/react-in-jsx-scope": "off",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": [
"warn",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
},
settings: {
react: {
version: "detect",
},
},
};
32 changes: 32 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
- OS: [e.g. macOS, Windows]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]

**Additional context**
Add any other context about the problem here.
20 changes: 20 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex: I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
31 changes: 31 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Fixes # (issue)

## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

- [ ] Test A
- [ ] Test B

## Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
89 changes: 89 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# ReadLite Browser Extension - AI Coding Guide

## Architecture Overview

**Plasmo-based browser extension** for distraction-free reading with shadow DOM isolation.

### Core Data Flow
```
User clicks icon → background.ts (TOGGLE_READER_MODE) → content.tsx (shadow DOM)
→ ReaderProvider → Reader.tsx → article parsed via parser.ts
```

### Key Files
- `src/background.ts` - Extension icon clicks, tab state tracking via `activeTabsMap`
- `src/content.tsx` - Shadow DOM host, theme sync via `syncThemeToShadow()`
- `src/components/reader/Reader.tsx` - Main UI, 1000+ lines (settings, highlights, export)
- `src/context/ReaderContext.tsx` - Global state: `article`, `settings`, `isLoading`
- `src/utils/parser.ts` - Readability + DOMPurify with strict `SANITIZE_CONFIG` whitelist

### Message Types (background ↔ content)
```typescript
type: "TOGGLE_READER_MODE" | "READER_MODE_CHANGED" | "CONTENT_SCRIPT_READY"
```

## Development Commands

```bash
# CRITICAL: Always build Tailwind first - it's a separate step
npm run dev # Chrome (includes Tailwind build)
npm run dev:firefox # Firefox target
npm run build # Production Chrome
npm run package # Create store-ready .zip
```

**Testing**: Load `build/chrome-mv3-prod/` as unpacked extension. Check both background console (chrome://extensions → Inspect) and page console.

## Code Conventions

### Imports
```typescript
// Use ~/* alias for src/* paths (tsconfig.json)
import { createLogger } from "~/utils/logger"
```

### Logging (required for new modules)
```typescript
const logger = createLogger("module-name") // Initialize at file top
logger.info("Message", data) // Use throughout
```

### Styling (Tailwind + CSS Variables)
```tsx
// Use theme-aware classes that map to --readlite-* CSS variables
<div className="bg-primary text-primary"> // NOT bg-white
<div className="text-secondary border"> // Theme-adaptive
```

Theme tokens defined in `src/config/theme.ts`, mapped in `tailwind.config.js`.

### Settings Pattern
```typescript
const { settings, updateSettings, isSettingsLoaded } = useStoredSettings()
// Always check isSettingsLoaded before using settings
```

Storage key: `readlite-settings` via `@plasmohq/storage`. Version migrations handled in hook.

## Critical Patterns

### Shadow DOM Isolation
Content script runs in isolated world. Theme changes must propagate via:
1. `applyThemeStyles(shadowRoot, theme)` - Sets CSS variables
2. `syncThemeToShadow()` - Updates wrapper classes + dispatches event

### Content Sanitization
Parser uses strict DOMPurify whitelist. To allow new attributes/tags, update `SANITIZE_CONFIG` in `parser.ts`.

### Highlight Persistence
- `highlightStorage.ts` - Per-URL storage via Plasmo storage
- `highlightAnchor.ts` - Text anchoring for cross-session restoration
- Colors: `beige`, `cyan`, `lavender`, `olive`, `peach`

## i18n
- Source: `locales/{en,zh}/messages.json`
- Access: `const { t } = useI18n()` then `t("keyName")`
- Manifest uses `__MSG_keyName__` format

## Extension Manifest
Defined in `package.json` `manifest` field (Plasmo convention), not separate file. Web-accessible resources include `src/styles/tailwind.output.css`.
17 changes: 17 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
groups:
dev-dependencies:
dependency-type: "development"
update-types:
- "minor"
- "patch"
production-dependencies:
dependency-type: "production"
update-types:
- "patch"
45 changes: 45 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x, 20.x]

steps:
- uses: actions/checkout@v4

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build Tailwind
run: npm run build:tailwind

- name: Check formatting
run: npx prettier --check "src/**/*.{ts,tsx,css,json}"

- name: Lint
run: npm run lint

- name: Test
run: npm test

- name: Build Extension (Chrome)
run: npm run build

- name: Build Extension (Firefox)
run: npm run build:firefox
24 changes: 11 additions & 13 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,52 +1,50 @@
# 依赖目录
# Dependencies
node_modules/
pnpm-lock.yaml
package-lock.json
yarn.lock

# 构建输出
# Dist
dist/
build/

# Plasmo 特有目录
# Plasmo specific directories
.plasmo/
out/

# 开发环境
# Development environment
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# 编译缓存
# TurboRepo and caching
.turbo/
.cache/
*.tsbuildinfo

# 日志
# Logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# 编辑器目录
# Editor directories
.idea/
.vscode/
.vim/
*.sublime-workspace
*.sublime-project

# 系统文件
# System files
.DS_Store
Thumbs.db
ehthumbs.db
Desktop.ini

# 临时文件
# Temporary files
*.swp
*.swo
*~
*.tmp
*.bak
.cursor/
.cursor/
coverage/
16 changes: 16 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Dependencies
node_modules/

# Build outputs
dist/
build/
.plasmo/

# Generated files
src/styles/tailwind.output.css

# Lockfiles
package-lock.json

# Coverage
coverage/
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": true,
"trailingComma": "all",
"singleQuote": false,
"printWidth": 80,
"tabWidth": 2
}
Loading