Skip to content

feat: image import hover preview and docs#78

Merged
zmrlft merged 6 commits intozmrlft:mainfrom
NB-Group:feat/image-import-preview
Feb 8, 2026
Merged

feat: image import hover preview and docs#78
zmrlft merged 6 commits intozmrlft:mainfrom
NB-Group:feat/image-import-preview

Conversation

@NB-Group
Copy link
Contributor

@NB-Group NB-Group commented Feb 4, 2026

概要

  • New: Image → Contribution Heatmap: 上传 PNG/JPG/SVG,自动缩放到 7 行、1~52 列,按亮度映射 0/1/3/6/9;支持反转亮度、亮度阈值(低于阈值先清零再量化);悬停日历预览。
  • Docs: 更新 README/README_zh,加入新功能说明。

运行时说明

  • 为避免纯前端 dev 环境缺少 Wails runtime 时崩溃,将 BrowserOpenURL / EventsOn 改为按需动态 import 并加存在性判断;在有 Wails 的打包环境下仍调用相同 API,功能不变。
  • 如需我再补充测试说明或 Issue 引用,请告

(话说readme里的图要更新一下呢?我看有人在重写readme要不交给他吧())


Summary by cubic

Added image-to-contribution heatmap import with hover preview, supporting PNG/JPG/SVG and brightness mapping with auto/binary quantisation, smoothing, invert, and threshold controls. Updated docs and made Wails runtime calls safe in dev to prevent crashes.

  • New Features

    • Image import card: upload PNG/JPG/SVG; auto size to 1–7 rows and 1–52 columns with manual overrides.
    • Quantisation: auto (quantiles) or binary (Otsu) to 0/1/3/6/9; invert, optional brightness threshold clearing; scaling filter (nearest/bilinear); stroke recovery via threshold relaxation (primary/secondary).
    • Hover preview on the calendar; left-click to apply, right-click to cancel.
    • Added i18n strings (EN/ZH) and README quick guide with examples.
  • Bug Fixes

    • Prevent dev-mode crashes by lazily importing Wails APIs (BrowserOpenURL, EventsOn, Go methods) with existence checks; packaged app behavior unchanged.

Written for commit 79ea7f6. Summary will update on new commits.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 9 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="frontend/src/App.tsx">

<violation number="1" location="frontend/src/App.tsx:110">
P2: Async dynamic import in the effect can register `EventsOn` after unmount, leaving an uncleaned listener and possible state updates on an unmounted component.</violation>
</file>

<file name="frontend/src/components/ImageImportCard.tsx">

<violation number="1" location="frontend/src/components/ImageImportCard.tsx:159">
P2: processImage closes over `threshold` but its useCallback dependency array only includes `t`, so threshold changes won't be reflected when reprocessing the image. Include `threshold` in the dependency array to avoid stale values.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

setGithubUser(status.user);
return;
let unsubscribe: (() => void) | undefined;
(async () => {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Async dynamic import in the effect can register EventsOn after unmount, leaving an uncleaned listener and possible state updates on an unmounted component.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/App.tsx, line 110:

<comment>Async dynamic import in the effect can register `EventsOn` after unmount, leaving an uncleaned listener and possible state updates on an unmounted component.</comment>

<file context>
@@ -86,16 +106,28 @@ const AppLayout: React.FC<AppLayoutProps> = ({ contributions }) => {
-        setGithubUser(status.user);
-        return;
+    let unsubscribe: (() => void) | undefined;
+    (async () => {
+      try {
+        const { EventsOn } = await import('../wailsjs/runtime/runtime');
</file context>
Fix with Cubic

@zmrlft
Copy link
Owner

zmrlft commented Feb 4, 2026

@codex

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bdcb0f2c2e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +125 to +132
const w = img.naturalWidth || img.width;
const h = img.naturalHeight || img.height;
const suggestedWidth = clamp(Math.round((w / h) * 7), 1, 52);
setAutoWidth(suggestedWidth);

const finalWidth = clamp(widthOverride ?? suggestedWidth, 1, 52);
const finalHeight = 7;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard against SVGs with no intrinsic size

When an uploaded SVG lacks explicit width/height, img.naturalWidth/naturalHeight can be 0, so w / h yields NaN or Infinity. That flows into suggestedWidth/finalWidth and then into canvas.width, which can become 0/invalid and later cause getImageData to throw. This means some valid SVGs (e.g., viewBox-only assets exported from design tools) will fail to import. Consider falling back to a default width/height or parsing viewBox before computing suggestedWidth.

Useful? React with 👍 / 👎.

@NB-Group
Copy link
Contributor Author

NB-Group commented Feb 5, 2026

新功能:自动行列数。并在readme里更新了相应的成果与失败样例。

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 13 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="frontend/src/components/ImageImportCard.tsx">

<violation number="1" location="frontend/src/components/ImageImportCard.tsx:280">
P2: Failed image processing never updates lastProcessKey, so the reprocess effect sees a mismatch after isProcessing resets and repeatedly retries, causing an alert/processing loop on errors.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="frontend/src/components/ImageImportCard.tsx">

<violation number="1" location="frontend/src/components/ImageImportCard.tsx:132">
P2: Blob URLs created with URL.createObjectURL are not revoked on component unmount, so the active fileUrl can leak if the component unmounts while an image is loaded.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@zmrlft zmrlft merged commit 34e58d7 into zmrlft:main Feb 8, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants