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
20 changes: 16 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Card-Tab 更新日志

## [2026.06.19] - 个人定制版

### 新增功能
- 增加登录后可见的私密备注,未登录公开响应会移除备注字段
- 备注弹窗支持鼠标选中复制和一键复制
- 分类导航改为 All / 单分类视图切换,并同步地址栏 hash
- 设置模式下增强拖拽排序,支持拖到分类空白区域和空分类
- 添加重复 URL 时给出提醒,并允许继续添加
- 增加 Archive Yellow 主题

### 移除功能
- 移除原版天气组件、天气弹窗、城市搜索、IP 定位和天气代理接口
- 不再需要 `WEATHER_API_KEY` 和 `WEATHER_API_HOST` 环境变量

## [2026.01.08] - 天气组件集成

移除"我的导航"标题,集成和风天气组件
Expand All @@ -9,10 +23,8 @@
- 支持IP自动定位和手动切换城市,提供智能缓存机制
- 城市搜索功能:快速搜索并查看不同城市天气

### 配置说明
- [申请和风天气 API Key](https://id.qweather.com/#/register)(合理设置API限制)
- 配置API Key到环境变量 `WEATHER_API_KEY`
- [控制台设置]( https://console.qweather.com/setting) 中复制 “API Host”, 配置到环境变量 `WEATHER_API_HOST`
### 定制版说明
- 该天气功能已在 2026.06.19 个人定制版中移除

## [2026.01.03] - 浏览器扩展重构升级

Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
# Card-Tab 书签卡片式管理,进入管理模式可以自由移动书签位置,添加和删除书签,支持自定义网站分类,支持切换暗色主题
# Card-Tab 书签卡片式管理,进入设置模式可以移动书签位置,添加和删除书签,支持自定义网站分类、私密备注和多主题切换

📋 **查看完整更新历史**: [CHANGELOG.md](./CHANGELOG.md)

### [当前版本] - 2026.01.08
### [当前版本] - 2026.06.19 定制版
## ✨ 核心功能

### 🎨 界面设计
- **现代化视觉**:采用 Segoe UI 字体系统,米白色/深色双主题
- **卡片式布局**:美观的书签卡片,支持左侧装饰条和悬停效果
- **响应式设计**:完美适配桌面端和移动端设备
- **暗色主题**:一键切换,护眼舒适的夜间模式
- **多主题**:支持温暖浅色、Archive Yellow 和暗色主题

### 🔍 搜索功能
- **多引擎搜索**:支持百度、必应、谷歌、DuckDuckGo
- **书签搜索**:快速搜索已保存的书签名称和网址
- **分类导航**:快捷按钮一键跳转到指定分类
- **智能高亮**:自动高亮当前可见分类
- **分类导航**:支持 All 和单分类视图切换,地址栏 hash 可恢复当前分类

### 📚 书签管理
- **分类管理**:自定义分类,支持重命名和排序
- **卡片编辑**:修改名称、网址、描述和自定义图标
- **卡片编辑**:修改名称、网址、描述、私密备注和自定义图标
- **私密书签**:登录后可见的私密书签功能
- **拖拽排序**:直观的拖拽操作调整书签顺序
- **私密备注**:登录后通过备注图标查看,可选中复制或一键复制
- **拖拽排序**:设置模式下支持分类内排序和跨分类移动
- **重复提醒**:添加重复 URL 时提示已存在分类,并允许手动继续添加

### 🔐 安全特性
- **JWT验证**:基于Token的身份验证机制
Expand All @@ -30,11 +31,10 @@
- **权限控制**:公开/私密书签分级管理

### 📱 用户体验
- **自定义图标**:支持图片URL链接,个性化书签外观
- **自定义图标**:支持图片URL链接,留空时自动获取网站图标
- **悬停提示**:鼠标悬停显示书签详细描述
- **返回顶部**:便捷的页面导航功能
- **加载动画**:流畅的交互反馈和视觉效果
- **实时天气**:显示当前城市温度和天气状况,点击查看3天天气预报,支持城市切换和智能定位

### 注意:如果你已经部署过第一版(20240902)导航,更新workes代码后将无法看到之前保存的书签,需重新添加书签,望知悉!

Expand Down
73 changes: 73 additions & 0 deletions docs/superpowers/plans/2026-06-19-card-tab-custom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Card-Tab Customization Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Customize Card-Tab for private notes, tab-style category views, safer drag/drop, duplicate warnings, a warm archive theme, and removal of the weather feature.

**Architecture:** Keep the project as a single Cloudflare Worker file to preserve the original deployment model. Use small helper functions inside `workers.js`, avoid broad refactors, and add a dependency-free Node verification script for behavior checks that can run locally.

**Tech Stack:** Cloudflare Workers JavaScript, browser DOM APIs, local Node.js verification.

---

### Task 1: Add Local Verification

**Files:**
- Create: `test/customization.test.mjs`
- Modify: `workers.js`

- [x] Add a Node script that reads `workers.js` and asserts the agreed customization requirements.
- [x] Run the script before implementation and verify it fails on missing customization.
- [x] Run the script after each implementation slice.

### Task 2: Remove Weather

**Files:**
- Modify: `workers.js`
- Modify: `README.md`
- Modify: `CHANGELOG.md`

- [x] Remove the weather mini widget, modal, frontend weather code, styles, and `/api/weather/*` Worker routes.
- [x] Remove README and changelog instructions for `WEATHER_API_KEY` and `WEATHER_API_HOST`.
- [x] Verify `node --check workers.js` and `node test/customization.test.mjs`.

### Task 3: Private Notes

**Files:**
- Modify: `workers.js`

- [x] Add `privateNote` to add/edit dialogs and link objects.
- [x] Redact `privateNote` from unauthenticated `/api/getLinks` responses.
- [x] Add a logged-in note icon and modal with selectable text and copy button.
- [x] Preserve `privateNote` during drag/drop saves.
- [x] Verify syntax and customization tests.

### Task 4: Category Tab Views

**Files:**
- Modify: `workers.js`

- [x] Replace category scroll behavior with `All` plus category view switching.
- [x] Sync selected view to the URL hash and restore it on reload.
- [x] Keep settings mode compatible with `All` for cross-category management.
- [x] Verify syntax and customization tests.

### Task 5: Drag/Drop and Duplicate Warning

**Files:**
- Modify: `workers.js`

- [x] Keep drag/drop available only in settings mode.
- [x] Support category container drop targets, including empty categories.
- [x] Preserve all original link fields when saving order.
- [x] Warn when adding a duplicate normalized URL and allow the user to continue.
- [x] Verify syntax and customization tests.

### Task 6: Archive Yellow Theme

**Files:**
- Modify: `workers.js`

- [x] Add a three-state theme model: warm light, archive yellow, dark.
- [x] Keep the existing dark theme behavior while allowing the archive palette.
- [x] Verify syntax and customization tests.
33 changes: 33 additions & 0 deletions test/customization.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';

const source = readFileSync(new URL('../workers.js', import.meta.url), 'utf8');

function assertAbsent(pattern, message) {
assert.equal(pattern.test(source), false, message);
}

function assertPresent(pattern, message) {
assert.equal(pattern.test(source), true, message);
}

assertAbsent(/WEATHER_API|weather-mini|\/api\/weather/, 'weather feature should be removed');
assertAbsent(/hitokoto|search-engine-select|search-container|search-button/, 'top quote and search bar should be removed');

assertPresent(/privateNote/, 'private notes should be represented in link data');
assertPresent(/sanitizeLinkForPublic|redactPrivateNote|privateNote:\s*undefined/, 'public responses should redact private notes');
assertPresent(/note-modal|showNoteModal|copyPrivateNote/, 'private note modal and copy behavior should exist');
assertPresent(/\/api\/favicon|resolveAutoFaviconUrl/, 'automatic favicon proxy should exist');
assertAbsent(/faviconextractor|api\.iowen/, 'old external favicon services should not be used');

assertPresent(/currentCategoryView/, 'category tab view state should exist');
assertPresent(/setCategoryView/, 'category navigation should switch views instead of scrolling');
assertPresent(/location\.hash|history\.replaceState/, 'category view should sync to the URL hash');

assertPresent(/drop-target|setupDropContainers|card-container[^]*dragover/, 'category containers should be drop targets');
assertPresent(/\.\.\.originalLink|Object\.assign\(\{\},\s*originalLink/, 'drag saves should preserve all link fields');

assertPresent(/findDuplicateLink|duplicate/i, 'duplicate URL warning should exist');
assertPresent(/archive-theme|Archive Yellow|archive yellow/i, 'archive yellow theme should exist');
assertPresent(/exportJsonBackup|导出JSON/, 'JSON export should exist');
assertPresent(/triggerJsonImport|handleJsonImport|json-import-input/, 'JSON import should exist');
Loading