@ondrej-svec/hog 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -4845,47 +4845,69 @@ var init_repos_panel = __esm({
4845
4845
 
4846
4846
  // src/board/components/issue-row.tsx
4847
4847
  import { Box as Box20, Text as Text19 } from "ink";
4848
- import { Fragment as Fragment3, jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
4848
+ import { jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
4849
4849
  function truncate(s, max) {
4850
4850
  return s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
4851
4851
  }
4852
- function formatTargetDate(dateStr) {
4853
- if (!dateStr) return { text: "", color: "gray" };
4854
- const d = new Date(dateStr);
4855
- const days = Math.ceil((d.getTime() - Date.now()) / 864e5);
4856
- if (days < 0) return { text: `${Math.abs(days)}d overdue`, color: "red" };
4857
- if (days === 0) return { text: "today", color: "yellow" };
4858
- if (days === 1) return { text: "tomorrow", color: "white" };
4859
- if (days <= 7) return { text: `in ${days}d`, color: "white" };
4860
- return {
4861
- text: d.toLocaleDateString("en-US", { month: "short", day: "numeric" }),
4862
- color: "gray"
4863
- };
4864
- }
4865
- function timeAgo2(dateStr) {
4866
- const seconds = Math.floor((Date.now() - new Date(dateStr).getTime()) / 1e3);
4867
- if (seconds < 60) return "now";
4852
+ function formatDate2(issue) {
4853
+ if (issue.targetDate) {
4854
+ const d = new Date(issue.targetDate);
4855
+ const days2 = Math.ceil((d.getTime() - Date.now()) / 864e5);
4856
+ if (days2 < 0) return { text: `${Math.abs(days2)}d overdue`, color: "red" };
4857
+ if (days2 === 0) return { text: "today", color: "yellow" };
4858
+ if (days2 === 1) return { text: "tomorrow", color: "white" };
4859
+ if (days2 <= 7) return { text: `in ${days2}d`, color: "white" };
4860
+ return {
4861
+ text: d.toLocaleDateString("en-US", { month: "short", day: "numeric" }),
4862
+ color: "gray"
4863
+ };
4864
+ }
4865
+ const seconds = Math.floor((Date.now() - new Date(issue.updatedAt).getTime()) / 1e3);
4866
+ if (seconds < 60) return { text: "now", color: "gray" };
4868
4867
  const minutes = Math.floor(seconds / 60);
4869
- if (minutes < 60) return `${minutes}m`;
4868
+ if (minutes < 60) return { text: `${minutes}m`, color: "gray" };
4870
4869
  const hours = Math.floor(minutes / 60);
4871
- if (hours < 24) return `${hours}h`;
4870
+ if (hours < 24) return { text: `${hours}h`, color: "gray" };
4872
4871
  const days = Math.floor(hours / 24);
4873
- if (days < 30) return `${days}d`;
4872
+ if (days < 30) return { text: `${days}d`, color: "gray" };
4874
4873
  const months = Math.floor(days / 30);
4875
- return `${months}mo`;
4874
+ return { text: `${months}mo`, color: "gray" };
4875
+ }
4876
+ function compactLabel(name) {
4877
+ const lc = name.toLowerCase();
4878
+ const colon = lc.indexOf(":");
4879
+ if (colon < 0) return PLAIN_ABBREVS[lc] ?? name.slice(0, 5);
4880
+ const key = lc.slice(0, colon);
4881
+ const val = name.slice(colon + 1);
4882
+ if (key === "size") return val.slice(0, 3).toUpperCase();
4883
+ if (key === "priority") return `p:${val.slice(0, 1).toUpperCase()}`;
4884
+ if (key === "work") return "WIP";
4885
+ return `${key.slice(0, 2)}:${val.slice(0, 2)}`;
4876
4886
  }
4877
4887
  function labelColor(name) {
4878
- return LABEL_COLORS[name.toLowerCase()] ?? "cyan";
4879
- }
4880
- function IssueRow({ issue, selfLogin, isSelected }) {
4888
+ const lc = name.toLowerCase();
4889
+ if (lc === "bug" || lc === "urgent" || lc.startsWith("priority:h") || lc.startsWith("priority:c"))
4890
+ return "red";
4891
+ if (lc.startsWith("priority:m") || lc.startsWith("work:")) return "yellow";
4892
+ if (lc.startsWith("priority:l") || lc === "wontfix") return "gray";
4893
+ if (lc.startsWith("size:")) return "white";
4894
+ if (lc === "feature" || lc === "enhancement") return "green";
4895
+ if (lc === "documentation") return "blue";
4896
+ if (lc === "good first issue") return "magenta";
4897
+ return "cyan";
4898
+ }
4899
+ function IssueRow({ issue, selfLogin, isSelected, panelWidth }) {
4881
4900
  const assignees = issue.assignees ?? [];
4882
4901
  const isSelf = assignees.some((a) => a.login === selfLogin);
4883
4902
  const isUnassigned = assignees.length === 0;
4884
4903
  const assigneeColor = isSelf ? "green" : isUnassigned ? "gray" : "white";
4885
- const assigneeText = isUnassigned ? "unassigned" : truncate(assignees.map((a) => a.login).join(", "), 14);
4904
+ const assigneeText = isUnassigned ? "unassigned" : truncate(assignees.map((a) => a.login).join(", "), ASSIGN_W);
4886
4905
  const labels = (issue.labels ?? []).slice(0, 2);
4887
- const target = formatTargetDate(issue.targetDate);
4888
- const titleStr = truncate(issue.title, 42).padEnd(42);
4906
+ const date = formatDate2(issue);
4907
+ const innerW = panelWidth - 2;
4908
+ const titleW = Math.max(8, innerW - FIXED_OVERHEAD);
4909
+ const titleStr = truncate(issue.title, titleW).padEnd(titleW);
4910
+ const dateStr = date.text.padStart(DATE_W);
4889
4911
  return /* @__PURE__ */ jsxs21(Box20, { children: [
4890
4912
  isSelected ? /* @__PURE__ */ jsx21(Text19, { color: "cyan", bold: true, children: "\u25B6 " }) : /* @__PURE__ */ jsx21(Text19, { children: " " }),
4891
4913
  /* @__PURE__ */ jsxs21(Text19, { color: "cyan", children: [
@@ -4893,49 +4915,57 @@ function IssueRow({ issue, selfLogin, isSelected }) {
4893
4915
  String(issue.number).padEnd(5)
4894
4916
  ] }),
4895
4917
  /* @__PURE__ */ jsx21(Text19, { children: " " }),
4896
- isSelected ? /* @__PURE__ */ jsx21(Text19, { color: "white", bold: true, children: titleStr }) : /* @__PURE__ */ jsx21(Text19, { children: titleStr }),
4918
+ isSelected ? /* @__PURE__ */ jsx21(Text19, { bold: true, color: "white", children: titleStr }) : /* @__PURE__ */ jsx21(Text19, { children: titleStr }),
4897
4919
  /* @__PURE__ */ jsx21(Text19, { children: " " }),
4898
- /* @__PURE__ */ jsx21(Box20, { width: LABEL_COL_WIDTH, children: labels.map((l, i) => /* @__PURE__ */ jsxs21(Text19, { children: [
4920
+ /* @__PURE__ */ jsx21(Box20, { width: LABEL_W, overflow: "hidden", children: labels.length === 0 ? /* @__PURE__ */ jsx21(Text19, { color: "gray", children: " ".repeat(LABEL_W) }) : labels.map((l, i) => /* @__PURE__ */ jsxs21(Text19, { children: [
4899
4921
  i > 0 ? " " : "",
4900
4922
  /* @__PURE__ */ jsxs21(Text19, { color: labelColor(l.name), children: [
4901
4923
  "[",
4902
- truncate(l.name, 12),
4924
+ compactLabel(l.name),
4903
4925
  "]"
4904
4926
  ] })
4905
4927
  ] }, l.name)) }),
4906
4928
  /* @__PURE__ */ jsx21(Text19, { children: " " }),
4907
- /* @__PURE__ */ jsx21(Text19, { color: assigneeColor, children: assigneeText.padEnd(14) }),
4929
+ /* @__PURE__ */ jsx21(Text19, { color: assigneeColor, children: assigneeText.padEnd(ASSIGN_W) }),
4908
4930
  /* @__PURE__ */ jsx21(Text19, { children: " " }),
4909
- /* @__PURE__ */ jsx21(Text19, { color: "gray", children: timeAgo2(issue.updatedAt).padStart(4) }),
4910
- target.text ? /* @__PURE__ */ jsxs21(Fragment3, { children: [
4911
- /* @__PURE__ */ jsx21(Text19, { children: " " }),
4912
- /* @__PURE__ */ jsx21(Text19, { color: target.color, children: target.text })
4913
- ] }) : null
4931
+ /* @__PURE__ */ jsx21(Text19, { color: date.color, children: dateStr })
4914
4932
  ] });
4915
4933
  }
4916
- var LABEL_COLORS, LABEL_COL_WIDTH;
4934
+ var PLAIN_ABBREVS, CURSOR_W, NUM_W, LABEL_W, ASSIGN_W, DATE_W, FIXED_OVERHEAD;
4917
4935
  var init_issue_row = __esm({
4918
4936
  "src/board/components/issue-row.tsx"() {
4919
4937
  "use strict";
4920
- LABEL_COLORS = {
4921
- bug: "red",
4922
- enhancement: "green",
4923
- feature: "green",
4924
- documentation: "blue",
4925
- "good first issue": "magenta",
4926
- help: "yellow",
4927
- question: "yellow",
4928
- urgent: "red",
4929
- wontfix: "gray"
4938
+ PLAIN_ABBREVS = {
4939
+ bug: "bug",
4940
+ feature: "feat",
4941
+ enhancement: "enh",
4942
+ documentation: "docs",
4943
+ "good first issue": "gfi",
4944
+ help: "help",
4945
+ question: "?",
4946
+ urgent: "urg!",
4947
+ wontfix: "wont",
4948
+ task: "task"
4930
4949
  };
4931
- LABEL_COL_WIDTH = 30;
4950
+ CURSOR_W = 2;
4951
+ NUM_W = 7;
4952
+ LABEL_W = 13;
4953
+ ASSIGN_W = 10;
4954
+ DATE_W = 10;
4955
+ FIXED_OVERHEAD = CURSOR_W + NUM_W + 1 + LABEL_W + 1 + ASSIGN_W + 1 + DATE_W;
4932
4956
  }
4933
4957
  });
4934
4958
 
4935
4959
  // src/board/components/row-renderer.tsx
4936
4960
  import { Box as Box21, Text as Text20 } from "ink";
4937
4961
  import { jsx as jsx22, jsxs as jsxs22 } from "react/jsx-runtime";
4938
- function RowRenderer({ row, selectedId, selfLogin, isMultiSelected }) {
4962
+ function RowRenderer({
4963
+ row,
4964
+ selectedId,
4965
+ selfLogin,
4966
+ isMultiSelected,
4967
+ panelWidth = 120
4968
+ }) {
4939
4969
  switch (row.type) {
4940
4970
  case "sectionHeader": {
4941
4971
  const arrow = row.isCollapsed ? "\u25B6" : "\u25BC";
@@ -4990,7 +5020,15 @@ function RowRenderer({ row, selectedId, selfLogin, isMultiSelected }) {
4990
5020
  const checkbox2 = isMultiSelected != null ? isMultiSelected ? "\u2611 " : "\u2610 " : "";
4991
5021
  return /* @__PURE__ */ jsxs22(Box21, { children: [
4992
5022
  checkbox2 ? /* @__PURE__ */ jsx22(Text20, { color: isMultiSelected ? "cyan" : "gray", children: checkbox2 }) : null,
4993
- /* @__PURE__ */ jsx22(IssueRow, { issue: row.issue, selfLogin, isSelected: selectedId === row.navId })
5023
+ /* @__PURE__ */ jsx22(
5024
+ IssueRow,
5025
+ {
5026
+ issue: row.issue,
5027
+ selfLogin,
5028
+ isSelected: selectedId === row.navId,
5029
+ panelWidth
5030
+ }
5031
+ )
4994
5032
  ] });
4995
5033
  }
4996
5034
  case "activity": {
@@ -5065,10 +5103,10 @@ var init_statuses_panel = __esm({
5065
5103
  // src/board/components/toast-container.tsx
5066
5104
  import { Spinner as Spinner3 } from "@inkjs/ui";
5067
5105
  import { Box as Box23, Text as Text22 } from "ink";
5068
- import { Fragment as Fragment4, jsx as jsx24, jsxs as jsxs24 } from "react/jsx-runtime";
5106
+ import { Fragment as Fragment3, jsx as jsx24, jsxs as jsxs24 } from "react/jsx-runtime";
5069
5107
  function ToastContainer({ toasts }) {
5070
5108
  if (toasts.length === 0) return null;
5071
- return /* @__PURE__ */ jsx24(Box23, { flexDirection: "column", children: toasts.map((t) => /* @__PURE__ */ jsx24(Box23, { children: t.type === "loading" ? /* @__PURE__ */ jsxs24(Fragment4, { children: [
5109
+ return /* @__PURE__ */ jsx24(Box23, { flexDirection: "column", children: toasts.map((t) => /* @__PURE__ */ jsx24(Box23, { children: t.type === "loading" ? /* @__PURE__ */ jsxs24(Fragment3, { children: [
5072
5110
  /* @__PURE__ */ jsx24(Spinner3, { label: "" }),
5073
5111
  /* @__PURE__ */ jsxs24(Text22, { color: "cyan", children: [
5074
5112
  " ",
@@ -5104,7 +5142,7 @@ import { execFileSync as execFileSync3, spawnSync as spawnSync4 } from "child_pr
5104
5142
  import { Spinner as Spinner4 } from "@inkjs/ui";
5105
5143
  import { Box as Box24, Text as Text23, useApp, useStdout } from "ink";
5106
5144
  import { useCallback as useCallback12, useEffect as useEffect9, useMemo as useMemo3, useRef as useRef13, useState as useState16 } from "react";
5107
- import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs25 } from "react/jsx-runtime";
5145
+ import { Fragment as Fragment4, jsx as jsx25, jsxs as jsxs25 } from "react/jsx-runtime";
5108
5146
  function resolveStatusGroups(statusOptions, configuredGroups) {
5109
5147
  if (configuredGroups && configuredGroups.length > 0) {
5110
5148
  return configuredGroups.map((entry) => {
@@ -5801,6 +5839,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
5801
5839
  row,
5802
5840
  selectedId: nav.selectedId,
5803
5841
  selfLogin: config2.board.assignee,
5842
+ panelWidth: issuesPanelWidth,
5804
5843
  isMultiSelected: ui.state.mode === "multiSelect" && row.navId ? multiSelect.isSelected(row.navId) : void 0
5805
5844
  },
5806
5845
  row.key
@@ -5851,10 +5890,10 @@ function Dashboard({ config: config2, options, activeProfile }) {
5851
5890
  dateStr
5852
5891
  ] }),
5853
5892
  /* @__PURE__ */ jsx25(Text23, { children: " " }),
5854
- isRefreshing ? /* @__PURE__ */ jsxs25(Fragment5, { children: [
5893
+ isRefreshing ? /* @__PURE__ */ jsxs25(Fragment4, { children: [
5855
5894
  /* @__PURE__ */ jsx25(Spinner4, { label: "" }),
5856
5895
  /* @__PURE__ */ jsx25(Text23, { color: "cyan", children: " Refreshing..." })
5857
- ] }) : /* @__PURE__ */ jsxs25(Fragment5, { children: [
5896
+ ] }) : /* @__PURE__ */ jsxs25(Fragment4, { children: [
5858
5897
  /* @__PURE__ */ jsx25(RefreshAge, { lastRefresh }),
5859
5898
  consecutiveFailures > 0 ? /* @__PURE__ */ jsx25(Text23, { color: "red", children: " (!)" }) : null
5860
5899
  ] }),
@@ -7142,7 +7181,7 @@ function resolveProjectId(projectId) {
7142
7181
  process.exit(1);
7143
7182
  }
7144
7183
  var program = new Command();
7145
- program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.12.0").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
7184
+ program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.13.0").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
7146
7185
  const opts = thisCommand.opts();
7147
7186
  if (opts.json) setFormat("json");
7148
7187
  if (opts.human) setFormat("human");