diff --git a/CHANGELOG.md b/CHANGELOG.md
index db01809..8420aea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
deletion (#33, #43, #46, #48).
- Windows: six-second reversible deletion for individual and selected tasks
(#47).
+- Linux: the About dialog now carries the same website and Report-an-Issue
+ links as macOS and Windows (GtkAboutDialog cannot hold a second link,
+ so the dialog is built on the plain family layout); Windows and Linux
+ also gain the About © line, and the README and product site name the
+ issue tracker as the feedback channel (#55).
### Changed
- Add an executable cross-platform product acceptance contract. Windows,
diff --git a/README.md b/README.md
index c0221c3..41e29cb 100644
--- a/README.md
+++ b/README.md
@@ -135,6 +135,16 @@ suite and byte-identical i18n on every push. The source-controlled
verified package, and accessibility-driven product behavior on Windows,
macOS arm64/x64, and Linux.
+## Feedback
+
+Taskly is offline-first and ships no telemetry —
+[GitHub issues](https://github.com/turinglambdaai/taskly/issues) are the
+feedback channel, with templates for both
+[bug reports](https://github.com/turinglambdaai/taskly/issues/new?template=bug_report.md)
+and
+[feature requests](https://github.com/turinglambdaai/taskly/issues/new?template=feature_request.md).
+The in-app About dialog links to the same tracker on every platform.
+
## License
[AGPL-3.0](LICENSE).
diff --git a/README.zh-CN.md b/README.zh-CN.md
index a11f5ac..185f4d3 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -83,6 +83,10 @@ python3 shared/cli-golden/runner.py --binary scripts/taskly-cli.sh # 63 例 go
一套规格保证所有端一致:产品行为([PRODUCT-SPEC](shared/spec/PRODUCT-SPEC.md))、数据格式、CLI 契约、设计令牌、更新契约——都在 [shared/spec/](shared/spec/) 下。CI 在每次推送时用 golden 套件和字节级一致的 i18n 强制执行 CLI 契约;源码中的 `rivet-acceptance.rktd` 还要求 Windows、macOS arm64/x64、Linux 分别通过真实 RVT1、原生构建、已验证安装包和无障碍树驱动的产品行为验收。
+## 反馈
+
+Taskly 本地优先、无遥测,反馈统一走 [GitHub issues](https://github.com/turinglambdaai/taskly/issues):[Bug 报告](https://github.com/turinglambdaai/taskly/issues/new?template=bug_report.md)和[功能请求](https://github.com/turinglambdaai/taskly/issues/new?template=feature_request.md)都有模板。各平台的「关于」对话框内也有同一入口。
+
## 许可证
[AGPL-3.0](LICENSE)。
diff --git a/docs/index.html b/docs/index.html
index 9921a28..ffc2439 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -242,6 +242,7 @@
开放核心 · AGPL-3.0
GitHub
Rivet
更新日志
+ 问题反馈
© 2026 Taskly. AGPL-3.0 协议。
diff --git a/docs/script.js b/docs/script.js
index c1a9d9b..644e526 100644
--- a/docs/script.js
+++ b/docs/script.js
@@ -142,6 +142,7 @@ const i18n = {
'cta.manual': 'Read the manual',
'release.note': 'Every release carries SHA256SUMS plus a signed update manifest; macOS builds are ad-hoc signed \u2014 clear the Gatekeeper quarantine with `xattr -cr /Applications/Taskly.app` on first launch.',
'footer.changelog': 'Changelog',
+ 'footer.feedback': 'Feedback',
'footer.license': 'AGPL-3.0 license.'
},
zh: {
@@ -196,6 +197,7 @@ const i18n = {
'cta.manual': '阅读手册',
'release.note': '每个版本都带 SHA256SUMS 与签名更新清单;macOS 包为 ad-hoc 签名——首次启动如被 Gatekeeper 拦截,执行 `xattr -cr /Applications/Taskly.app` 即可。',
'footer.changelog': '更新日志',
+ 'footer.feedback': '问题反馈',
'footer.license': 'AGPL-3.0 协议。'
}
};
diff --git a/linux/src/main.cpp b/linux/src/main.cpp
index e298069..4d714cb 100644
--- a/linux/src/main.cpp
+++ b/linux/src/main.cpp
@@ -1774,20 +1774,56 @@ void confirm_dialog(char const* title, char const* body,
gtk_window_present(GTK_WINDOW(dialog));
}
+// Same About content as the macOS and Windows hosts: tagline, license,
+// and two links — website plus the issue tracker. GtkAboutDialog cannot
+// carry a second link, so the family layout is built on a plain dialog;
+// GtkLinkButton opens the URI through the system browser itself.
void show_about_dialog() {
- auto* dialog = gtk_about_dialog_new();
- gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), "Taskly");
- gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), rivet_app::kVersion);
- gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog),
- tr("aboutContent").c_str());
- gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog),
- tr("aboutLicense").c_str());
- gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog),
- "https://taskly.jrtx.site");
- gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog),
- tr("aboutWebsite").c_str());
- gtk_window_set_transient_for(GTK_WINDOW(dialog), g_state.window);
- gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ auto* dialog = gtk_dialog_new_with_buttons(
+ ("Taskly v" + std::string(rivet_app::kVersion)).c_str(),
+ g_state.window,
+ static_cast(GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT),
+ tr("dialogConfirm").c_str(), GTK_RESPONSE_CLOSE, nullptr);
+ auto* area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ auto* content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
+ gtk_widget_set_margin_top(content, 12);
+ gtk_widget_set_margin_bottom(content, 6);
+ gtk_widget_set_margin_start(content, 12);
+ gtk_widget_set_margin_end(content, 12);
+ gtk_box_append(GTK_BOX(area), content);
+ auto* copyright = gtk_label_new("© 2026 Taskly Team");
+ gtk_widget_set_opacity(copyright, 0.75);
+ gtk_box_append(GTK_BOX(content), copyright);
+ auto* comments = gtk_label_new(tr("aboutContent").c_str());
+ gtk_label_set_wrap(GTK_LABEL(comments), TRUE);
+ gtk_label_set_justify(GTK_LABEL(comments), GTK_JUSTIFY_CENTER);
+ gtk_label_set_max_width_chars(GTK_LABEL(comments), 60);
+ gtk_box_append(GTK_BOX(content), comments);
+ auto* license = gtk_label_new(tr("aboutLicense").c_str());
+ gtk_label_set_wrap(GTK_LABEL(license), TRUE);
+ gtk_label_set_justify(GTK_LABEL(license), GTK_JUSTIFY_CENTER);
+ gtk_label_set_max_width_chars(GTK_LABEL(license), 60);
+ gtk_widget_set_opacity(license, 0.75);
+ gtk_box_append(GTK_BOX(content), license);
+ auto* links = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 24);
+ gtk_widget_set_halign(links, GTK_ALIGN_CENTER);
+ gtk_box_append(GTK_BOX(content), links);
+ auto* website = gtk_link_button_new("https://taskly.jrtx.site");
+ gtk_button_set_label(GTK_BUTTON(website), tr("aboutWebsite").c_str());
+ gtk_widget_set_hexpand(website, FALSE);
+ gtk_box_append(GTK_BOX(links), website);
+ auto* issue = gtk_link_button_new(
+ "https://github.com/turinglambdaai/taskly/issues");
+ gtk_button_set_label(GTK_BUTTON(issue), tr("aboutReportIssue").c_str());
+ gtk_widget_set_hexpand(issue, FALSE);
+ gtk_box_append(GTK_BOX(links), issue);
+ g_signal_connect(
+ dialog, "response",
+ G_CALLBACK(+[](GtkDialog* dialog, gint, gpointer) {
+ gtk_window_destroy(GTK_WINDOW(dialog));
+ }),
+ nullptr);
gtk_window_present(GTK_WINDOW(dialog));
}
diff --git a/shared/spec/PRODUCT-SPEC.md b/shared/spec/PRODUCT-SPEC.md
index c07dd0d..9d1efba 100644
--- a/shared/spec/PRODUCT-SPEC.md
+++ b/shared/spec/PRODUCT-SPEC.md
@@ -168,9 +168,10 @@ pickers. Save (blank text silently ignored), Delete (confirm first), Cancel
- Help: About — `Taskly v` + `© 2026 Taskly Team` +
`aboutContent` + license line (`aboutLicense`) + two link buttons on
every host: Website (`aboutWebsite` → taskly.jrtx.site) and Report an
- Issue (`aboutReportIssue` → the GitHub issue tracker). Linux uses the
- GTK about dialog's native version/license/website rows; macOS and
- Windows render the same fields inside their sheet/dialog.
+ Issue (`aboutReportIssue` → the GitHub issue tracker). macOS and
+ Windows render the fields inside their sheet/dialog; Linux builds the
+ same layout on a plain GtkDialog — GtkAboutDialog cannot carry a
+ second link, so the native about dialog is not used.
- All accelerators work window-wide without opening the menu.
## 9. Reminders (all platforms)
diff --git a/windows/MainWindow.xaml.cpp b/windows/MainWindow.xaml.cpp
index 70e0858..43eae6c 100644
--- a/windows/MainWindow.xaml.cpp
+++ b/windows/MainWindow.xaml.cpp
@@ -2427,6 +2427,12 @@ winrt::fire_and_forget MainWindow::OnAbout(
Microsoft::UI::Xaml::RoutedEventArgs const&) {
auto panel = mxc::StackPanel{};
panel.Spacing(4);
+ auto copyright = mxc::TextBlock{};
+ copyright.Text(L"© 2026 Taskly Team");
+ copyright.TextAlignment(mx::TextAlignment::Center);
+ copyright.FontSize(12);
+ copyright.Opacity(0.75);
+ panel.Children().Append(copyright);
auto tagline = mxc::TextBlock{};
tagline.Text(t("aboutContent"));
tagline.TextAlignment(mx::TextAlignment::Center);