Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 2 additions & 2 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Layout from './components/Layout';
import Home from './views/Home';
import Write from './views/Write';
import QuestionDetail from './views/QuestionDetail';
import DarkMatter from './views/DarkMatter';
import WanderingPlanet from './views/WanderingPlanet';
import Privacy from './views/Privacy';
import About from './views/About';
import { AppProvider } from './contexts/AppContext';
Expand All @@ -21,7 +21,7 @@ const AnimatedRoutes: React.FC = () => {
<Route path="/" element={<Home />} />
<Route path="/write" element={<Write />} />
<Route path="/question/:id" element={<QuestionDetail />} />
<Route path="/dark-matter" element={<DarkMatter />} />
<Route path="/wandering-planet" element={<WanderingPlanet />} />
<Route path="/about" element={<About />} />
<Route path="/privacy" element={<Privacy />} />
</Routes>
Expand Down
183 changes: 92 additions & 91 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,91 +1,92 @@
1| # Cognitive Space
2|
3| Cognitive Space is a web application designed to help users organize and explore their thoughts, questions, and ideas. It allows you to drop unstructured thoughts, promote them into structured questions, and build context with claims, evidence, and triggers. Visualize connections between questions to uncover emerging patterns.
4|
5| Built with React for the frontend and deployed as a Cloudflare Worker for the backend API.
6|
7| ## Features
8|
9| - **Thought Capture**: Quickly jot down ideas without structure.
10| - **Question Organization**: Promote thoughts into questions and add supporting elements.
11| - **Visualization**: Explore relationships between questions graphically.
12| - **Dark Matter Recovery**: Rescue orphaned thoughts and link them back.
13| - **PWA Support**: Installable as a progressive web app.
14|
15| ## Guide
16|
17| 1. Open the app and use `Just write` to drop a thought without worrying about structure.
18| 2. Create a new Question by tagging or promoting a thought when the theme becomes clear.
19| 3. Add supporting notes as Claims, Evidence, or Triggers to build context over time.
20| 4. Use `Visualize` to explore related questions and spot emerging clusters.
21| 5. Visit `Dark Matter` to rescue orphaned fragments and link them to a question.
22|
23| For more details, see [Product Design](docs/product_design.md) and [Visualization Proposal](docs/visualization_proposal.md).
24|
25| ## Prerequisites
26|
27| - Node.js (version 16 or higher)
28| - Cloudflare Wrangler CLI (`npm install -g wrangler`)
29|
30| ## Installation
31|
32| 1. Clone the repository:
33| ```bash
34| git clone https://github.com/mingzhangyang/cognitive-space
35| cd cognitive-space
36| ```
37|
38| 2. Install dependencies:
39| ```bash
40| npm install
41| ```
42|
43| ## Local Development
44|
45| 1. Set the `BIGMODEL_API_KEY` secret using Wrangler:
46| ```bash
47| wrangler secret put BIGMODEL_API_KEY
48| ```
49|
50| 2. Run the Worker locally (builds assets first):
51| ```bash
52| npm run dev
53| ```
54|
55| 3. Optional: Run UI-only dev server (no Worker API):
56| ```bash
57| npm run dev:ui
58| ```
59|
60| ## Deployment
61|
62| 1. Build the static assets:
63| ```bash
64| npm run build
65| ```
66|
67| 2. Deploy the Worker:
68| ```bash
69| npm run deploy
70| ```
71|
72| ## Configuration
73|
74| - `BIGMODEL_API_KEY`: Required. Your API key for the AI model.
75| - `BIGMODEL_MODEL`: Optional. Defaults to `glm-4.5-flash`. Specify a different model if needed.
76|
77| ## Scripts
78|
79| - `npm run build`: Builds the static assets.
80| - `npm run dev`: Runs the Worker locally.
81| - `npm run dev:ui`: Runs the UI dev server.
82| - `npm run deploy`: Deploys to Cloudflare.
83|
84| ## Contributing
85|
86| Contributions are welcome! Please read the contributing guidelines (if any) before submitting a pull request.
87|
88| ## License
89|
90| This project is licensed under the MIT License.
91|
# Cognitive Space

Cognitive Space is a web application designed to help users organize and explore their thoughts, questions, and ideas. It allows you to drop unstructured thoughts, promote them into structured questions, and build context with claims, evidence, and triggers. Visualize connections between questions to uncover emerging patterns.

Built with React for the frontend and deployed as a Cloudflare Worker for the backend API.

## Features

- **Thought Capture**: Quickly jot down ideas without structure.
- **Question Organization**: Promote thoughts into questions and add supporting elements.
- **Visualization**: Explore relationships between questions graphically.
- **Wandering Planet Recovery**: Rescue orphaned thoughts and link them back.
- **PWA Support**: Installable as a progressive web app.

## Guide

1. Open the app and use `Just write` to drop a thought without worrying about structure.
2. Create a new Question by tagging or promoting a thought when the theme becomes clear.
3. Add supporting notes as Claims, Evidence, or Triggers to build context over time.
4. Use `Visualize` to explore related questions and spot emerging clusters.
5. Visit `Wandering Planet` to rescue orphaned fragments and link them to a question.

For more details, see [Product Design](docs/product_design.md) and [Visualization Proposal](docs/visualization_proposal.md).

## Prerequisites

- Node.js (version 18 or higher)
- Cloudflare Wrangler CLI (`npm install -g wrangler`)

## Installation

1. Clone the repository:
```bash
git clone https://github.com/mingzhangyang/cognitive-space
cd cognitive-space
```

2. Install dependencies:
```bash
npm install
```

## Local Development

1. Set the `BIGMODEL_API_KEY` secret using Wrangler:
```bash
wrangler secret put BIGMODEL_API_KEY
```

2. Run the Worker locally (builds assets first):
```bash
npm run dev
```

3. Optional: Run UI-only dev server (no Worker API):
```bash
npm run dev:ui
```

## Deployment

1. Build the static assets:
```bash
npm run build
```

2. Deploy the Worker:
```bash
npm run deploy
```

## Configuration

- `BIGMODEL_API_KEY`: Required. Your API key for the AI model.
- `BIGMODEL_MODEL`: Optional. Defaults to `glm-4.7-flashx`. Specify a different model if needed.
- `VITE_BUILD_ID`: Optional. Injected by build scripts for service worker cache versioning. Override to control the cache tag.

## Scripts

- `npm run build`: Builds the static assets.
- `npm run dev`: Runs the Worker locally.
- `npm run dev:ui`: Runs the UI dev server.
- `npm run preview`: Builds the assets and runs the Worker locally.
- `npm run deploy`: Deploys to Cloudflare.

## Contributing

Contributions are welcome! Please read the contributing guidelines (if any) before submitting a pull request.

## License

This project is licensed under the MIT License.
12 changes: 7 additions & 5 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
- **想法捕捉**: 快速记录没有结构的想法。
- **问题整理**: 将想法提升为问题,并添加支持元素。
- **可视化**: 图形化地探索问题之间的关系。
- **暗物质恢复**: 拯救孤立的想法并将它们重新链接起来。
- **流浪天体恢复**: 拯救孤立的想法并将它们重新链接起来。
- **PWA支持**: 可安装为渐进式Web应用。

## 使用指南
Expand All @@ -18,13 +18,13 @@
2. 当主题明确时,通过标记或提升想法,创建一个新的问题。
3. 随着时间的推移,添加论点、证据或触发器等支持内容来构建背景。
4. 使用“Visualize”功能探索相关问题,找到新出现的聚集点。
5. 访问“Dark Matter”版块,拯救孤立的碎片并将它们链接到一个问题。
5. 访问“流浪天体”版块,拯救孤立的碎片并将它们链接到一个问题。

更多详情,请参考[产品设计](docs/product_design.md)和[可视化提案](docs/visualization_proposal.md)。

## 先决条件

- Node.js(版本16或更高
- Node.js(版本18或更高
- Cloudflare Wrangler CLI(`npm install -g wrangler`)

## 安装
Expand Down Expand Up @@ -72,13 +72,15 @@
## 配置

- `BIGMODEL_API_KEY`: 必需,AI模型的API密钥。
- `BIGMODEL_MODEL`: 可选,默认为`glm-4.5-flash`。如需使用其它模型,请指定。
- `BIGMODEL_MODEL`: 可选,默认为`glm-4.7-flashx`。如需使用其它模型,请指定。
- `VITE_BUILD_ID`: 可选。构建脚本会自动注入用于 Service Worker 缓存版本控制,可手动覆盖以固定缓存标签。

## 脚本

- `npm run build`: 构建静态资源。
- `npm run dev`: 本地运行Worker服务。
- `npm run dev:ui`: 运行UI开发服务器。
- `npm run preview`: 构建资源并本地运行Worker服务。
- `npm run deploy`: 部署到Cloudflare。

## 贡献
Expand All @@ -87,4 +89,4 @@

## 许可证

此项目基于MIT许可证授权。
此项目基于MIT许可证授权。
14 changes: 12 additions & 2 deletions components/ActionIconButton.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { useAppContext } from '../contexts/AppContext';
import { CopyIcon, EditIcon, TrashIcon } from './Icons';
import { CopyIcon, CopyToIcon, EditIcon, MoveIcon, TrashIcon } from './Icons';
import Tooltip from './Tooltip';

type ActionKind = 'edit' | 'copy' | 'delete';
type ActionKind = 'edit' | 'copy' | 'copy_to' | 'delete' | 'move';

type ActionIconButtonProps = {
action: ActionKind;
Expand All @@ -27,10 +27,20 @@ const actionConfig: Record<ActionKind, { labelKey: string; hoverClassName: strin
hoverClassName: 'hover:text-warning dark:hover:text-warning-dark',
Icon: CopyIcon
},
copy_to: {
labelKey: 'copy_to_question',
hoverClassName: 'hover:text-accent dark:hover:text-accent-dark',
Icon: CopyToIcon
},
delete: {
labelKey: 'delete',
hoverClassName: 'hover:text-red-500 dark:hover:text-red-400',
Icon: TrashIcon
},
move: {
labelKey: 'move_to_question',
hoverClassName: 'hover:text-accent dark:hover:text-accent-dark',
Icon: MoveIcon
}
};

Expand Down
6 changes: 4 additions & 2 deletions components/ActionSheetButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useAppContext } from '../contexts/AppContext';
import { CopyIcon, EditIcon, TrashIcon, MoveIcon } from './Icons';
import { CopyIcon, CopyToIcon, EditIcon, TrashIcon, MoveIcon } from './Icons';

/**
* CSS class used for action sheet option text to ensure a unified muted color
Expand All @@ -12,10 +12,11 @@ export const UNIFIED_TEXT_CLASS = 'text-muted-400 dark:text-muted-500';
* Action kinds supported by the action sheet.
* - `edit`: edit the item
* - `copy`: copy the item content
* - `copy_to`: copy the item to another question
* - `delete`: remove the item
* - `move`: move the item to another question
*/
export type ActionKind = 'edit' | 'copy' | 'delete' | 'move';
export type ActionKind = 'edit' | 'copy' | 'copy_to' | 'delete' | 'move';

/**
* Props for `ActionSheetButton`.
Expand All @@ -39,6 +40,7 @@ const actionConfig: Record<
> = {
edit: { labelKey: 'edit', textClassName: UNIFIED_TEXT_CLASS, Icon: EditIcon },
copy: { labelKey: 'copy_note', textClassName: UNIFIED_TEXT_CLASS, Icon: CopyIcon },
copy_to: { labelKey: 'copy_to_question', textClassName: UNIFIED_TEXT_CLASS, Icon: CopyToIcon },
delete: { labelKey: 'delete', textClassName: UNIFIED_TEXT_CLASS, Icon: TrashIcon },
move: { labelKey: 'move_to_question', textClassName: UNIFIED_TEXT_CLASS, Icon: MoveIcon }
};
Expand Down
9 changes: 9 additions & 0 deletions components/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ export const CopyIcon = ({ className }: { className?: string }) => (
</svg>
);

export const CopyToIcon = ({ className }: { className?: string }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" className={className}>
<rect x="9" y="9" width="12" height="12" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
<line x1="18" y1="5" x2="18" y2="9"></line>
<line x1="16" y1="7" x2="20" y2="7"></line>
</svg>
);

export const CheckIcon = ({ className }: { className?: string }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" className={className}>
<polyline points="20 6 9 17 4 12"></polyline>
Expand Down
22 changes: 11 additions & 11 deletions components/MessageCenterPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import { coerceConfidenceLabel } from '../utils/confidence';
const isNoteSuggestion = (message: AssistantMessage): message is Extract<AssistantMessage, { kind: 'note_suggestion' }> =>
message.kind === 'note_suggestion';

const isDarkMatterReady = (message: AssistantMessage): message is Extract<AssistantMessage, { kind: 'dark_matter_ready' }> =>
message.kind === 'dark_matter_ready';
const isWanderingPlanetReady = (message: AssistantMessage): message is Extract<AssistantMessage, { kind: 'wandering_planet_ready' }> =>
message.kind === 'wandering_planet_ready';

const getConfidenceLabelText = (label: string, t: (key: string) => string) => {
if (label === 'likely') return t('dark_matter_ai_confidence_likely');
if (label === 'possible') return t('dark_matter_ai_confidence_possible');
return t('dark_matter_ai_confidence_loose');
if (label === 'likely') return t('wandering_planet_ai_confidence_likely');
if (label === 'possible') return t('wandering_planet_ai_confidence_possible');
return t('wandering_planet_ai_confidence_loose');
};

const buildNoteSuggestionDetails = (payload: NoteSuggestionPayload, t: (key: string) => string) => {
Expand Down Expand Up @@ -109,7 +109,7 @@ const MessageCenterPanel: React.FC<{ isOpen: boolean; onClose: () => void }> = (
{runningJobs.map((job) => {
const jobLabel = job.kind === 'note_analysis'
? translate('assistant_job_note')
: formatTemplate(translate('assistant_job_dark_matter'), { count: job.meta?.noteCount ?? 0 });
: formatTemplate(translate('assistant_job_wandering_planet'), { count: job.meta?.noteCount ?? 0 });
return (
<div key={job.id} className="surface-card p-3 flex items-start gap-3">
<LoadingSpinner className="w-4 h-4 text-accent dark:text-accent-dark mt-0.5" />
Expand Down Expand Up @@ -184,26 +184,26 @@ const MessageCenterPanel: React.FC<{ isOpen: boolean; onClose: () => void }> = (
);
}

if (isDarkMatterReady(message)) {
if (isWanderingPlanetReady(message)) {
const count = message.payload.suggestionCount;
return (
<div key={message.id} className="surface-card p-4 space-y-3">
<div>
<p className="text-body-sm-muted">{translate('assistant_suggestion_dark_matter')}</p>
<p className="text-body-sm-muted">{translate('assistant_suggestion_wandering_planet')}</p>
<p className="text-ink dark:text-ink-dark text-base font-medium">
{formatTemplate(translate('assistant_dark_matter_ready_title'), { count })}
{formatTemplate(translate('assistant_wandering_planet_ready_title'), { count })}
</p>
</div>
<div className="flex flex-wrap gap-2 pt-2">
<button
type="button"
onClick={() => {
navigate('/dark-matter');
navigate('/wandering-planet');
onClose();
}}
className="px-3 py-1.5 rounded-full bg-ink text-white dark:bg-muted-600 hover:opacity-90 transition-opacity text-xs"
>
{translate('assistant_suggestion_open_dark_matter')}
{translate('assistant_suggestion_open_wandering_planet')}
</button>
<button
type="button"
Expand Down
Loading
Loading