Skip to content

Commit 855c233

Browse files
committed
CozyTag: browser-native bookmark manager
0 parents  commit 855c233

48 files changed

Lines changed: 15122 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/deploy.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: [master]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: pages
15+
cancel-in-progress: true
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
- uses: actions/setup-node@v4
23+
with:
24+
node-version: 22
25+
cache: npm
26+
- run: npm ci
27+
- run: npm run build
28+
- uses: actions/configure-pages@v5
29+
- uses: actions/upload-pages-artifact@v3
30+
with:
31+
path: dist
32+
33+
deploy:
34+
needs: build
35+
runs-on: ubuntu-latest
36+
environment:
37+
name: github-pages
38+
url: ${{ steps.deployment.outputs.page_url }}
39+
steps:
40+
- id: deployment
41+
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# dependencies
2+
node_modules/
3+
4+
# build output
5+
dist/
6+
.astro/
7+
8+
# local test artifacts
9+
test-output/
10+
shots-v2/
11+
e2e-result.json
12+
shoot2.log
13+
*.log
14+
15+
# local test fixtures
16+
bg.jpg
17+
bookmarks_*.html
18+
19+
# workbuddy memory
20+
.workbuddy/
21+
22+
# os
23+
.DS_Store
24+
Thumbs.db

README.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<p align="right">
2+
<a href="./README_zh-CN.md">简体中文</a>
3+
</p>
4+
5+
<p align="center">
6+
<img src="./assets/readme/hero.svg" width="100%" alt="CozyTag">
7+
</p>
8+
9+
<p align="center">
10+
<img src="https://img.shields.io/badge/Astro-7-0d9488?style=flat-square" alt="Astro 7">
11+
<img src="https://img.shields.io/badge/TypeScript-5.9-0d9488?style=flat-square" alt="TypeScript 5.9">
12+
<img src="https://img.shields.io/badge/storage-IndexedDB-0d9488?style=flat-square" alt="IndexedDB">
13+
<img src="https://img.shields.io/badge/build-single--file%20HTML-14b8a6?style=flat-square" alt="Single-file HTML">
14+
</p>
15+
16+
CozyTag is a bookmark manager that runs entirely in your own browser. No backend, no login, no data collection — bookmarks, folders, icons, and preferences all stay in your browser's IndexedDB. The build output is a single HTML file you can double-click to open and use offline.
17+
18+
## Why
19+
20+
Most bookmark tools fall into two camps: browser built-ins tied to cloud accounts (Chrome/Edge), or third-party services that require you to trust a server (Raindrop/Pinboard). CozyTag sits in between — **you keep the organizing power, and your data stays local**:
21+
22+
- **Your data, your machine** — Import once and everything lands in IndexedDB. Close the tab, data stays. Clear browser storage, it's gone. No server ever sees it.
23+
- **Take it anywhere**`npm run build` produces one HTML file with all JS/CSS inlined. Put it on a USB drive, email it, host it on an intranet server. Works offline.
24+
- **Smooth with thousands** — Virtual grid rendering with absolute positioning and DOM node pooling keeps ~40 cards in the DOM even with 1700+ bookmarks. Zero layout jank.
25+
- **Import and export, lossless** — Reads Chrome/Edge/Firefox bookmark files, de-duplicates and merges folders on import. Export back to standard Netscape HTML, re-import with no loss.
26+
27+
<p align="center">
28+
<img src="./assets/readme/workflow.svg" width="100%" alt="Workflow">
29+
</p>
30+
31+
<p align="center">
32+
<img src="./assets/readme/section-features.svg" width="100%" alt="Features">
33+
</p>
34+
35+
| Feature | What it does |
36+
|---|---|
37+
| Offline-first | IndexedDB storage, zero network requests, works in private mode |
38+
| Single file | Build output is one HTML file, no external dependencies |
39+
| Virtual scroll | Node pooling keeps thousands of bookmarks scrolling smoothly |
40+
| Views | Grid / list / compact, with scroll position preserved |
41+
| Smart folders | Recent / starred / uncategorized / duplicates, one click away |
42+
| Import wizard | Parse, preview, de-duplicate, merge, then import in bulk |
43+
| Lossless export | Standard Netscape HTML, re-importable |
44+
| Command palette | `Ctrl / ⌘ + K` for keyboard-first navigation |
45+
| Edit mode | Card actions stay visible; click selects instead of opening |
46+
| Custom background | Image / GIF / video ≤10MB, adjustable opacity and position |
47+
| Themes | 8-color palette, derived colors generated live with `color-mix` |
48+
| Dark mode | Layered surfaces and four-step grays for clear hierarchy |
49+
| Keyboard | Palette / search / undo / import / export / arrow navigation |
50+
| Undo | Delete, move, and bulk actions can all be rolled back |
51+
52+
## Getting started
53+
54+
```bash
55+
npm install # install dependencies
56+
npm run dev # local dev server
57+
npm run check # type check
58+
npm run build # build → dist/CozyTag.html (single file)
59+
```
60+
61+
After building, double-click `dist/CozyTag.html` to use it offline in any modern browser. On first open, click **Import** in the top-right and drop in the `.html` bookmark file your browser exports.
62+
63+
End-to-end tests (build first):
64+
65+
```bash
66+
node scripts/e2e.mjs # headless
67+
node scripts/e2e.mjs --headed # with browser UI
68+
```
69+
70+
## Tech stack
71+
72+
- **Framework** — Astro 7 (build only, zero runtime hydration)
73+
- **Language** — TypeScript 5.9
74+
- **Styles** — SCSS + CSS custom properties (design tokens)
75+
- **Storage** — IndexedDB (folders / bookmarks / icons / meta)
76+
- **Tests** — Playwright (44-assertion e2e suite)
77+
- **Bundling**`scripts/bundle-single-file.mjs` inlines the Astro output into one HTML file
78+
79+
## Project structure
80+
81+
```
82+
CozyTag/
83+
├── src/
84+
│ ├── lib/
85+
│ │ ├── app.ts # entry: wire up views, shortcuts, background layer
86+
│ │ ├── db.ts # IndexedDB layer (four stores + batch transactions)
87+
│ │ ├── state.ts # in-memory index + event bus + undo stack
88+
│ │ ├── netscape.ts # Netscape bookmark parser
89+
│ │ ├── virtual.ts # virtual grid: absolute positioning + node pool
90+
│ │ └── ui/ # topbar / sidebar / list / import / export / palette
91+
│ ├── pages/index.astro # single page + skeleton
92+
│ └── styles/ # design tokens + layered styles
93+
├── scripts/
94+
│ ├── bundle-single-file.mjs
95+
│ └── e2e.mjs
96+
└── package.json
97+
```
98+
99+
## Design notes
100+
101+
Three principles: a neutral base with switchable accent color, a dark mode with real hierarchy, and animations that never touch layout.
102+
103+
- **Color** — Clean neutral gray in light mode, slightly muted (not pure black) in dark mode so surfaces can float. Default accent is teal (`#0d9488`), with 7 more to switch between; all derived colors come from `color-mix`.
104+
- **Motion** — Only `transform` and `opacity`, never layout. The topbar hides with an absolute-positioned `translateY` on the compositor; the sidebar transitions via `grid-template-columns`; the virtual grid uses `translate3d`. Respects `prefers-reduced-motion`.
105+
- **Interaction** — Card action buttons stay hidden by default to avoid mis-clicks; in edit mode they stay visible and a click selects. Hover feedback uses a border and glow.
106+
107+
## License
108+
109+
Internal project. For development or issues, contact the maintainer.
110+

README_zh-CN.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<p align="right">
2+
<a href="./README.md">English</a>
3+
</p>
4+
5+
<p align="center">
6+
<img src="./assets/readme/hero-zh.svg" width="100%" alt="CozyTag">
7+
</p>
8+
9+
<p align="center">
10+
<img src="https://img.shields.io/badge/Astro-7-0d9488?style=flat-square" alt="Astro 7">
11+
<img src="https://img.shields.io/badge/TypeScript-5.9-0d9488?style=flat-square" alt="TypeScript 5.9">
12+
<img src="https://img.shields.io/badge/storage-IndexedDB-0d9488?style=flat-square" alt="IndexedDB">
13+
<img src="https://img.shields.io/badge/build-single--file%20HTML-14b8a6?style=flat-square" alt="单文件 HTML">
14+
</p>
15+
16+
CozyTag 是一个完全在你自己浏览器里跑的书签管理台。没有后端、不用登录、不采集任何数据——书签、分类、图标、偏好全存在浏览器的 IndexedDB 里。构建出来的产物就是一个 HTML 文件,双击打开、断网也能用。
17+
18+
## 为什么做它
19+
20+
现在的书签工具大多是两种:要么是绑定浏览器账号的自带收藏夹(Chrome、Edge),分类不好用、跨设备得登录;要么是放在云端的第三方服务(Raindrop、Pinboard),好用但得把书签交给别人的服务器。CozyTag 想做中间那一档——**整理功能留下,数据留在你自己电脑上**
21+
22+
- **数据是你的** — 导入后全部存进浏览器的 IndexedDB。关掉标签页数据还在,清掉浏览器数据就彻底没了,没有任何服务器经手。
23+
- **随身带走**`npm run build` 会打出一个把 JS/CSS 全内联的 HTML 文件。放 U 盘、发邮件、挂内网都行,断网照样用。
24+
- **书签多也不卡** — 列表用虚拟滚动(绝对定位 + 节点复用),哪怕 1700 多条书签,页面里也只保留约 40 个节点,滚动不卡顿。
25+
- **导入导出不丢东西** — 认 Chrome / Edge / Firefox 导出的书签文件,导入时自动去重、合并同名分类;导出还是标准格式,能再原样导回来。
26+
27+
<p align="center">
28+
<img src="./assets/readme/workflow-zh.svg" width="100%" alt="工作流">
29+
</p>
30+
31+
<p align="center">
32+
<img src="./assets/readme/section-features-zh.svg" width="100%" alt="功能">
33+
</p>
34+
35+
| 功能 | 说明 |
36+
|---|---|
37+
| 离线优先 | 数据存 IndexedDB,零网络请求,隐私模式也能用 |
38+
| 单文件 | 构建产物是一个 HTML 文件,不依赖任何外部资源 |
39+
| 虚拟滚动 | 节点复用,上千条书签滚动依然顺滑 |
40+
| 多视图 | 网格 / 列表 / 紧凑三种,切换时保留滚动位置 |
41+
| 智能分类 | 最近添加 / 星标 / 未分类 / 重复项,一键切换 |
42+
| 导入向导 | 解析、预览、去重、合并,再批量入库 |
43+
| 无损导出 | 标准 Netscape HTML,可再次导入 |
44+
| 命令面板 | `Ctrl / ⌘ + K` 唤起,键盘流操作 |
45+
| 编辑模式 | 卡片操作按钮常驻,点击是选中而不是打开 |
46+
| 自定义背景 | 图片 / GIF / 视频 ≤10MB,不透明度和位置可调 |
47+
| 主题色 | 8 色调色板,派生色用 `color-mix` 实时生成 |
48+
| 暗色模式 | 分层表面 + 四档灰阶,层次清楚 |
49+
| 全键盘 | 面板 / 搜索 / 撤销 / 导入 / 导出 / 方向键导航 |
50+
| 撤销 | 删除、移动、批量操作都能一键撤回 |
51+
52+
## 快速开始
53+
54+
```bash
55+
npm install # 安装依赖
56+
npm run dev # 本地开发
57+
npm run check # 类型检查
58+
npm run build # 构建,产出 dist/CozyTag.html 单文件
59+
```
60+
61+
构建完成后,双击 `dist/CozyTag.html` 就能在任意现代浏览器离线使用。第一次打开点右上角「导入」,把浏览器导出的 `.html` 书签文件拖进去就行。
62+
63+
端到端测试(先 build):
64+
65+
```bash
66+
node scripts/e2e.mjs # 无界面
67+
node scripts/e2e.mjs --headed # 带界面
68+
```
69+
70+
## 技术栈
71+
72+
- **框架** — Astro 7(只用构建,运行时零 hydration)
73+
- **语言** — TypeScript 5.9
74+
- **样式** — SCSS + CSS 自定义属性(设计令牌)
75+
- **存储** — IndexedDB(folders / bookmarks / icons / meta 四表)
76+
- **测试** — Playwright(端到端 44 项断言)
77+
- **打包**`scripts/bundle-single-file.mjs`,把 Astro 产物内联成一个 HTML
78+
79+
## 项目结构
80+
81+
```
82+
CozyTag/
83+
├── src/
84+
│ ├── lib/
85+
│ │ ├── app.ts # 入口:装配视图、绑定快捷键、背景层
86+
│ │ ├── db.ts # IndexedDB 数据层(四表 + 批量事务)
87+
│ │ ├── state.ts # 内存索引 + 事件广播 + 撤销栈
88+
│ │ ├── netscape.ts # Netscape 书签解析器
89+
│ │ ├── virtual.ts # 虚拟网格:绝对定位 + 节点复用
90+
│ │ └── ui/ # 顶栏 / 侧栏 / 列表 / 导入导出 / 命令面板
91+
│ ├── pages/index.astro # 唯一页面 + 骨架屏
92+
│ └── styles/ # 设计令牌 + 分层样式
93+
├── scripts/
94+
│ ├── bundle-single-file.mjs
95+
│ └── e2e.mjs
96+
└── package.json
97+
```
98+
99+
## 设计理念
100+
101+
三条原则:中性底 + 可切换的主题色,有层次的暗色模式,不碰布局的动效。
102+
103+
- **配色** — 亮色用干净的中性灰,暗色不用纯黑、略沉,好让表面浮起来。默认玉青(`#0d9488`),另有 7 色可切,所有派生色由 `color-mix` 实时算出。
104+
- **动效** — 只用 `transform``opacity`,不触发布局。顶栏用绝对定位 + `translateY` 走合成层隐藏,侧栏用 `grid-template-columns` 过渡,虚拟滚动用 `translate3d`;尊重 `prefers-reduced-motion`
105+
- **交互** — 卡片操作按钮默认藏起来防误触;编辑模式下常驻、点击为选中。悬停用边框 + 光晕反馈。
106+
107+
## 许可
108+
109+
内部项目。二次开发或反馈问题请联系维护者。

assets/readme/hero-zh.svg

Lines changed: 80 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)