dsh-todo-time-log 0.5.2 → 0.6.1
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/README.md +177 -530
- package/lib/client.js +248 -103
- package/lib/index.js +42 -0
- package/package.json +14 -3
package/lib/client.js
CHANGED
|
@@ -592,6 +592,7 @@
|
|
|
592
592
|
"calendar.weekdaySun"
|
|
593
593
|
];
|
|
594
594
|
var TABLE_COLUMNS = [
|
|
595
|
+
{ key: "check", labelKey: "row.complete", sortBy: null, srOnly: true },
|
|
595
596
|
{ key: "title", labelKey: "table.title", sortBy: "title" },
|
|
596
597
|
{ key: "project", labelKey: "table.project", sortBy: "project" },
|
|
597
598
|
{ key: "status", labelKey: "table.status", sortBy: null },
|
|
@@ -625,8 +626,13 @@
|
|
|
625
626
|
overflow: hidden;
|
|
626
627
|
color: var(--dsw-alias-label-primary);
|
|
627
628
|
background: var(--dsw-alias-bg-base);
|
|
629
|
+
/* 与宿主 UI 同一套字体栈(真机继承宿主 body 字体):显式声明后,静态预览与真机一致,
|
|
630
|
+
也不会被祖先样式改掉。 */
|
|
631
|
+
font-family: var(--dsw-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
|
|
632
|
+
"Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif);
|
|
628
633
|
font-size: 14px;
|
|
629
634
|
line-height: 1.6;
|
|
635
|
+
-webkit-font-smoothing: antialiased;
|
|
630
636
|
}
|
|
631
637
|
.ttl-scroll {
|
|
632
638
|
flex: 1;
|
|
@@ -814,8 +820,9 @@
|
|
|
814
820
|
/* 数据区:视图/筛选控制与列表同属一张卡片,成为唯一的数据容器。 */
|
|
815
821
|
.ttl-data {
|
|
816
822
|
border: 0.5px solid var(--dsw-alias-border-l2);
|
|
817
|
-
border-radius: var(--dsw-radius-
|
|
823
|
+
border-radius: var(--dsw-radius-lg);
|
|
818
824
|
background: var(--dsw-alias-bg-base);
|
|
825
|
+
box-shadow: var(--dsw-shadow-lv1);
|
|
819
826
|
overflow: hidden;
|
|
820
827
|
}
|
|
821
828
|
.ttl-data > .ttl-toolbar {
|
|
@@ -1072,8 +1079,8 @@
|
|
|
1072
1079
|
display: inline-flex;
|
|
1073
1080
|
align-items: center;
|
|
1074
1081
|
flex: none;
|
|
1075
|
-
height:
|
|
1076
|
-
padding: 0
|
|
1082
|
+
height: 18px;
|
|
1083
|
+
padding: 0 7px;
|
|
1077
1084
|
border: 0;
|
|
1078
1085
|
border-radius: 9999px;
|
|
1079
1086
|
background: color-mix(in srgb, var(--dsw-alias-label-secondary) 9%, transparent);
|
|
@@ -1087,19 +1094,36 @@
|
|
|
1087
1094
|
background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);
|
|
1088
1095
|
color: var(--dsw-alias-state-success-primary);
|
|
1089
1096
|
}
|
|
1090
|
-
|
|
1091
|
-
.ttl-badge
|
|
1092
|
-
|
|
1093
|
-
|
|
1097
|
+
/* 状态:胶囊 + 状态点(颜色沿用胶囊文字色)。 */
|
|
1098
|
+
.ttl-status-badge::before {
|
|
1099
|
+
content: '';
|
|
1100
|
+
flex: none;
|
|
1101
|
+
width: 5px;
|
|
1102
|
+
height: 5px;
|
|
1103
|
+
margin-right: 4px;
|
|
1104
|
+
border-radius: 50%;
|
|
1105
|
+
background: currentColor;
|
|
1106
|
+
opacity: 0.9;
|
|
1094
1107
|
}
|
|
1095
|
-
.ttl-badge
|
|
1096
|
-
|
|
1097
|
-
|
|
1108
|
+
.ttl-badge-row { display: inline-flex; flex-wrap: nowrap; align-items: center; gap: 4px; }
|
|
1109
|
+
/* 类型:小号圆角矩形标签(与状态胶囊区分层级)。 */
|
|
1110
|
+
.ttl-badge.ttl-type-badge {
|
|
1111
|
+
border-radius: 5px;
|
|
1112
|
+
padding: 0 6px;
|
|
1113
|
+
font-size: 10.5px;
|
|
1114
|
+
letter-spacing: 0.02em;
|
|
1098
1115
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1116
|
+
/* 优先级:箭头 + 文字,不再用第二个彩色胶囊,避免「标签汤」。 */
|
|
1117
|
+
.ttl-badge.ttl-priority-badge {
|
|
1118
|
+
gap: 3px;
|
|
1119
|
+
padding: 0;
|
|
1120
|
+
background: none;
|
|
1121
|
+
font-weight: 500;
|
|
1102
1122
|
}
|
|
1123
|
+
.ttl-priority-arrow { font-size: 11px; line-height: 1; }
|
|
1124
|
+
.ttl-badge.ttl-priority-badge.ttl-priority-high { background: none; color: var(--dsw-alias-state-error-primary); }
|
|
1125
|
+
.ttl-badge.ttl-priority-badge.ttl-priority-medium { background: none; color: var(--dsw-alias-state-warn-label); }
|
|
1126
|
+
.ttl-badge.ttl-priority-badge.ttl-priority-low { background: none; color: var(--dsw-alias-label-tertiary); }
|
|
1103
1127
|
.ttl-priority-select select { min-width: 64px; }
|
|
1104
1128
|
.ttl-type-select select { min-width: 76px; }
|
|
1105
1129
|
.ttl-badge.ttl-type-bug {
|
|
@@ -1176,7 +1200,7 @@
|
|
|
1176
1200
|
gap: 2px;
|
|
1177
1201
|
}
|
|
1178
1202
|
.ttl-link {
|
|
1179
|
-
padding: 2px
|
|
1203
|
+
padding: 2px 3px;
|
|
1180
1204
|
border: 0;
|
|
1181
1205
|
border-radius: 6px;
|
|
1182
1206
|
background: none;
|
|
@@ -1246,10 +1270,11 @@
|
|
|
1246
1270
|
}
|
|
1247
1271
|
.ttl-skeleton-row {
|
|
1248
1272
|
display: grid;
|
|
1249
|
-
|
|
1273
|
+
/* 与 .ttl-table 的列宽同口径(标题吃剩余,状态列固定),骨架屏不跳列。 */
|
|
1274
|
+
grid-template-columns: 20px minmax(0, 1fr) 72px 132px 100px 100px 92px;
|
|
1250
1275
|
align-items: center;
|
|
1251
|
-
gap:
|
|
1252
|
-
height:
|
|
1276
|
+
gap: 12px;
|
|
1277
|
+
height: 42px;
|
|
1253
1278
|
padding: 0 12px;
|
|
1254
1279
|
border-bottom: 0.5px solid var(--dsw-alias-border-l1);
|
|
1255
1280
|
}
|
|
@@ -1300,14 +1325,34 @@
|
|
|
1300
1325
|
.ttl-board-edit .ttl-project-picker { flex: 1 1 100%; }
|
|
1301
1326
|
.ttl-calendar-entry-edit .ttl-project-picker { flex: 1 1 100%; }
|
|
1302
1327
|
.ttl-gantt-row-edit .ttl-project-picker { flex: 0 1 220px; }.ttl-badge-project {
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1328
|
+
display: inline-flex;
|
|
1329
|
+
align-items: center;
|
|
1330
|
+
gap: 5px;
|
|
1331
|
+
max-width: 100%;
|
|
1306
1332
|
padding: 0;
|
|
1307
1333
|
background: none;
|
|
1308
|
-
color: var(--dsw-alias-label-
|
|
1334
|
+
color: var(--dsw-alias-label-secondary);
|
|
1309
1335
|
font-weight: 400;
|
|
1310
1336
|
}
|
|
1337
|
+
.ttl-project-dot {
|
|
1338
|
+
flex: none;
|
|
1339
|
+
width: 6px;
|
|
1340
|
+
height: 6px;
|
|
1341
|
+
border-radius: 50%;
|
|
1342
|
+
background: var(--dsw-alias-label-tertiary);
|
|
1343
|
+
}
|
|
1344
|
+
.ttl-badge-project[data-tone='business'] .ttl-project-dot { background: var(--dsw-alias-state-business-primary); }
|
|
1345
|
+
.ttl-badge-project[data-tone='done'] .ttl-project-dot { background: var(--dsw-alias-state-done-primary); }
|
|
1346
|
+
.ttl-badge-project[data-tone='success'] .ttl-project-dot { background: var(--dsw-alias-state-success-primary); }
|
|
1347
|
+
.ttl-badge-project[data-tone='warn'] .ttl-project-dot { background: var(--dsw-alias-state-warn-primary); }
|
|
1348
|
+
.ttl-badge-project[data-tone='error'] .ttl-project-dot { background: var(--dsw-alias-state-error-primary); }
|
|
1349
|
+
.ttl-badge-project[data-tone='idle'] .ttl-project-dot { background: var(--dsw-alias-label-caption); }
|
|
1350
|
+
.ttl-project-name {
|
|
1351
|
+
min-width: 0;
|
|
1352
|
+
overflow: hidden;
|
|
1353
|
+
text-overflow: ellipsis;
|
|
1354
|
+
white-space: nowrap;
|
|
1355
|
+
}
|
|
1311
1356
|
.ttl-badge-project-none { color: var(--dsw-alias-label-caption); }
|
|
1312
1357
|
|
|
1313
1358
|
.ttl-list-group {
|
|
@@ -1616,22 +1661,33 @@
|
|
|
1616
1661
|
}
|
|
1617
1662
|
.ttl-table {
|
|
1618
1663
|
width: 100%;
|
|
1619
|
-
|
|
1664
|
+
/* 固定列宽:列宽只由 col 决定,不随标题长短跳动(否则长标题会挤扁状态列,徽标被迫换行)。 */
|
|
1665
|
+
table-layout: fixed;
|
|
1666
|
+
min-width: 860px;
|
|
1620
1667
|
border-collapse: collapse;
|
|
1621
1668
|
font-size: 13px;
|
|
1622
1669
|
}
|
|
1670
|
+
/* 列宽口径:标题吃掉剩余宽度,其余列固定,保证「状态」列永远放得下一行徽标。 */
|
|
1671
|
+
.ttl-col-check { width: 40px; }
|
|
1672
|
+
.ttl-col-project { width: 104px; }
|
|
1673
|
+
.ttl-col-status { width: 160px; }
|
|
1674
|
+
.ttl-col-createdAt { width: 126px; }
|
|
1675
|
+
.ttl-col-completedAt { width: 126px; }
|
|
1676
|
+
.ttl-col-actions { width: 118px; }
|
|
1623
1677
|
.ttl-th {
|
|
1624
|
-
height:
|
|
1678
|
+
height: 34px;
|
|
1625
1679
|
padding: 0 12px;
|
|
1626
|
-
border-bottom: 0.5px solid var(--dsw-alias-border-
|
|
1680
|
+
border-bottom: 0.5px solid var(--dsw-alias-border-l2);
|
|
1627
1681
|
background: var(--dsw-alias-bg-module-platform);
|
|
1628
|
-
color: var(--dsw-alias-label-
|
|
1629
|
-
font-size:
|
|
1682
|
+
color: var(--dsw-alias-label-tertiary);
|
|
1683
|
+
font-size: 11px;
|
|
1630
1684
|
font-weight: 500;
|
|
1631
|
-
line-height:
|
|
1685
|
+
line-height: 16px;
|
|
1686
|
+
letter-spacing: 0.02em;
|
|
1632
1687
|
text-align: left;
|
|
1633
1688
|
white-space: nowrap;
|
|
1634
1689
|
}
|
|
1690
|
+
.ttl-th-check { width: 40px; padding: 0 4px 0 12px; }
|
|
1635
1691
|
.ttl-th-right { text-align: right; }
|
|
1636
1692
|
.ttl-th-sortable { padding: 0; }
|
|
1637
1693
|
.ttl-th-button {
|
|
@@ -1639,14 +1695,15 @@
|
|
|
1639
1695
|
align-items: center;
|
|
1640
1696
|
gap: 4px;
|
|
1641
1697
|
width: 100%;
|
|
1642
|
-
height:
|
|
1698
|
+
height: 34px;
|
|
1643
1699
|
padding: 0 12px;
|
|
1644
1700
|
border: 0;
|
|
1645
1701
|
background: none;
|
|
1646
1702
|
color: inherit;
|
|
1647
1703
|
font: inherit;
|
|
1648
|
-
font-size:
|
|
1649
|
-
|
|
1704
|
+
font-size: 11px;
|
|
1705
|
+
letter-spacing: 0.02em;
|
|
1706
|
+
line-height: 16px;
|
|
1650
1707
|
text-align: left;
|
|
1651
1708
|
white-space: nowrap;
|
|
1652
1709
|
cursor: pointer;
|
|
@@ -1655,7 +1712,10 @@
|
|
|
1655
1712
|
.ttl-th-button:hover { color: var(--dsw-alias-label-primary); }
|
|
1656
1713
|
.ttl-th-button-active { color: var(--dsw-alias-label-primary); }
|
|
1657
1714
|
.ttl-th-arrow { color: var(--dsw-alias-label-tertiary); font-size: 9px; line-height: 1; }
|
|
1658
|
-
.ttl-table-row {
|
|
1715
|
+
.ttl-table-row {
|
|
1716
|
+
border-bottom: 0.5px solid var(--dsw-alias-border-l1);
|
|
1717
|
+
transition: background 0.12s ease-out;
|
|
1718
|
+
}
|
|
1659
1719
|
.ttl-table-row:hover { background: var(--dsw-alias-interactive-bg-hover); }
|
|
1660
1720
|
.ttl-table tbody tr:last-child { border-bottom: 0; }
|
|
1661
1721
|
.ttl-table-group-row .ttl-td {
|
|
@@ -1671,7 +1731,8 @@
|
|
|
1671
1731
|
vertical-align: middle;
|
|
1672
1732
|
line-height: 20px;
|
|
1673
1733
|
}
|
|
1674
|
-
.ttl-td-
|
|
1734
|
+
.ttl-td-check { width: 40px; padding: 11px 4px 11px 12px; }
|
|
1735
|
+
.ttl-td-title { max-width: none; }
|
|
1675
1736
|
.ttl-td-time {
|
|
1676
1737
|
color: var(--dsw-alias-label-tertiary);
|
|
1677
1738
|
font-size: 12px;
|
|
@@ -1681,7 +1742,17 @@
|
|
|
1681
1742
|
font-variant-numeric: tabular-nums;
|
|
1682
1743
|
}
|
|
1683
1744
|
.ttl-td-actions { text-align: right; white-space: nowrap; }
|
|
1745
|
+
/* 操作区默认压低,行 hover / 键盘聚焦时再提亮,避免整张表被按钮占满注意力。 */
|
|
1746
|
+
.ttl-td-actions .ttl-link { color: var(--dsw-alias-label-tertiary); }
|
|
1747
|
+
.ttl-td-actions .ttl-link:hover { color: var(--dsw-alias-label-primary); }
|
|
1748
|
+
.ttl-table-row:hover .ttl-td-actions .ttl-link,
|
|
1749
|
+
.ttl-table-row:focus-within .ttl-td-actions .ttl-link { color: var(--dsw-alias-label-secondary); }
|
|
1750
|
+
.ttl-td-actions .ttl-link.ttl-link-danger { color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 72%, transparent); }
|
|
1751
|
+
.ttl-table-row:hover .ttl-td-actions .ttl-link.ttl-link-danger,
|
|
1752
|
+
.ttl-td-actions .ttl-link.ttl-link-danger:hover { color: var(--dsw-alias-state-error-primary); }
|
|
1684
1753
|
.ttl-table-title-button {
|
|
1754
|
+
display: -webkit-box;
|
|
1755
|
+
width: 100%;
|
|
1685
1756
|
max-width: 100%;
|
|
1686
1757
|
padding: 0;
|
|
1687
1758
|
border: 0;
|
|
@@ -1692,10 +1763,15 @@
|
|
|
1692
1763
|
font-weight: 500;
|
|
1693
1764
|
line-height: 20px;
|
|
1694
1765
|
text-align: left;
|
|
1766
|
+
overflow: hidden;
|
|
1695
1767
|
overflow-wrap: anywhere;
|
|
1768
|
+
/* 最多两行:长标题截断为省略号,完整文案在 title 与「详情」里可见,行高保持稳定。 */
|
|
1769
|
+
-webkit-line-clamp: 2;
|
|
1770
|
+
-webkit-box-orient: vertical;
|
|
1696
1771
|
cursor: pointer;
|
|
1697
1772
|
}
|
|
1698
1773
|
.ttl-table-title-button:hover { color: var(--dsw-alias-state-business-primary); }
|
|
1774
|
+
.ttl-table-row[data-status='completed'] .ttl-table-title-button { color: var(--dsw-alias-label-secondary); }
|
|
1699
1775
|
.ttl-table-detail-row .ttl-td { padding: 0 12px 10px; }
|
|
1700
1776
|
|
|
1701
1777
|
.ttl-board {
|
|
@@ -1786,7 +1862,7 @@
|
|
|
1786
1862
|
.ttl-board-move-select { height: 24px; max-width: 150px; padding: 0 4px; border: 0.5px solid var(--dsw-alias-border-l3); border-radius: 6px; background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-secondary); font: inherit; font-size: 12px; cursor: pointer; }
|
|
1787
1863
|
.ttl-board-move-select:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 1px; }
|
|
1788
1864
|
.ttl-board-compact .ttl-board-card { gap: 2px; padding: 6px 28px 6px 32px; }
|
|
1789
|
-
.ttl-board-compact .ttl-board-check { top: 6px; left: 6px; width:
|
|
1865
|
+
.ttl-board-compact .ttl-board-check { top: 6px; left: 6px; width: 18px; height: 18px; }
|
|
1790
1866
|
.ttl-board-compact .ttl-board-more { top: 4px; right: 2px; }
|
|
1791
1867
|
.ttl-board-compact .ttl-board-card-title { -webkit-line-clamp: 1; }
|
|
1792
1868
|
.ttl-board-compact .ttl-board-card-files { display: none; }
|
|
@@ -1805,8 +1881,13 @@
|
|
|
1805
1881
|
gap: 4px;
|
|
1806
1882
|
padding: 9px 32px 9px 36px;
|
|
1807
1883
|
border: 0.5px solid var(--dsw-alias-border-l2);
|
|
1808
|
-
border-radius:
|
|
1884
|
+
border-radius: 12px;
|
|
1809
1885
|
background: var(--dsw-alias-bg-base);
|
|
1886
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
1887
|
+
}
|
|
1888
|
+
.ttl-board-card:hover {
|
|
1889
|
+
border-color: var(--dsw-alias-border-l3);
|
|
1890
|
+
box-shadow: var(--dsw-shadow-lv1);
|
|
1810
1891
|
}
|
|
1811
1892
|
.ttl-board-card-editing { padding: 9px 10px; }
|
|
1812
1893
|
.ttl-board-card-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
|
|
@@ -1835,30 +1916,30 @@
|
|
|
1835
1916
|
}
|
|
1836
1917
|
.ttl-board-project { display: inline-flex; align-items: center; gap: 4px; min-width: 0; max-width: 100%; }
|
|
1837
1918
|
.ttl-board-project-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
top: 8px;
|
|
1841
|
-
left: 8px;
|
|
1919
|
+
/* 勾选圈:表格行首与看板卡片共用(看板只额外负责定位)。 */
|
|
1920
|
+
.ttl-check {
|
|
1842
1921
|
display: inline-flex;
|
|
1843
1922
|
align-items: center;
|
|
1844
1923
|
justify-content: center;
|
|
1845
|
-
width:
|
|
1846
|
-
height:
|
|
1924
|
+
width: 20px;
|
|
1925
|
+
height: 20px;
|
|
1847
1926
|
padding: 0;
|
|
1848
|
-
border: 1.5px solid var(--dsw-alias-border-
|
|
1927
|
+
border: 1.5px solid var(--dsw-alias-border-l4);
|
|
1849
1928
|
border-radius: 50%;
|
|
1850
1929
|
background: none;
|
|
1851
1930
|
color: transparent;
|
|
1852
1931
|
cursor: pointer;
|
|
1932
|
+
transition: border-color 0.15s, background 0.15s, color 0.15s;
|
|
1853
1933
|
}
|
|
1854
|
-
.ttl-
|
|
1855
|
-
.ttl-
|
|
1934
|
+
.ttl-check:hover { border-color: var(--dsw-alias-state-success-primary); }
|
|
1935
|
+
.ttl-check[data-checked='true'] {
|
|
1856
1936
|
border-color: var(--dsw-alias-state-success-primary);
|
|
1857
1937
|
background: var(--dsw-alias-state-success-primary);
|
|
1858
1938
|
color: var(--dsw-alias-label-primary-foreground);
|
|
1859
1939
|
}
|
|
1860
|
-
.ttl-
|
|
1861
|
-
.ttl-
|
|
1940
|
+
.ttl-check:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 2px; }
|
|
1941
|
+
.ttl-check:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
1942
|
+
.ttl-board-check { position: absolute; top: 8px; left: 8px; }
|
|
1862
1943
|
.ttl-board-more {
|
|
1863
1944
|
position: absolute;
|
|
1864
1945
|
top: 6px;
|
|
@@ -2119,7 +2200,7 @@
|
|
|
2119
2200
|
.ttl-file-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2120
2201
|
.ttl-file-chip-icon { font-size: 10px; line-height: 1; }
|
|
2121
2202
|
.ttl-file-more { color: var(--dsw-alias-label-tertiary); font-size: 11px; line-height: 20px; }
|
|
2122
|
-
.ttl-title-cell { display: flex; flex-direction: column; align-items:
|
|
2203
|
+
.ttl-title-cell { display: flex; flex-direction: column; align-items: stretch; gap: 3px; min-width: 0; }
|
|
2123
2204
|
.ttl-board-card-files { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
|
|
2124
2205
|
.ttl-calendar-entry-files { display: flex; flex: 1 1 100%; flex-wrap: wrap; gap: 4px; }
|
|
2125
2206
|
.ttl-detail-files { display: flex; flex-wrap: wrap; gap: 4px; }
|
|
@@ -2495,6 +2576,16 @@
|
|
|
2495
2576
|
const name = normalizeProject(project);
|
|
2496
2577
|
return name === "" ? t("project.none") : name;
|
|
2497
2578
|
}
|
|
2579
|
+
var PROJECT_TONES = ["business", "done", "success", "warn", "error"];
|
|
2580
|
+
function projectTone(project) {
|
|
2581
|
+
const name = normalizeProject(project);
|
|
2582
|
+
if (name === "") return "idle";
|
|
2583
|
+
let hash = 0;
|
|
2584
|
+
for (let index = 0; index < name.length; index += 1) {
|
|
2585
|
+
hash = hash * 31 + name.charCodeAt(index) | 0;
|
|
2586
|
+
}
|
|
2587
|
+
return PROJECT_TONES[Math.abs(hash) % PROJECT_TONES.length];
|
|
2588
|
+
}
|
|
2498
2589
|
function compareProjectNames(left, right) {
|
|
2499
2590
|
if (left === right) return 0;
|
|
2500
2591
|
if (left === "") return 1;
|
|
@@ -2824,6 +2915,7 @@
|
|
|
2824
2915
|
(index) => h(
|
|
2825
2916
|
"div",
|
|
2826
2917
|
{ key: index, className: "ttl-skeleton-row" },
|
|
2918
|
+
bar(true),
|
|
2827
2919
|
bar(),
|
|
2828
2920
|
bar(),
|
|
2829
2921
|
bar(true),
|
|
@@ -2886,7 +2978,54 @@
|
|
|
2886
2978
|
function ProjectBadge(props) {
|
|
2887
2979
|
const project = normalizeProject(props && props.project);
|
|
2888
2980
|
const className = project === "" ? "ttl-badge ttl-badge-project ttl-badge-project-none" : "ttl-badge ttl-badge-project";
|
|
2889
|
-
return h(
|
|
2981
|
+
return h(
|
|
2982
|
+
"span",
|
|
2983
|
+
{ className, title: projectLabel(project), "data-tone": projectTone(project) },
|
|
2984
|
+
h("span", { className: "ttl-project-dot", "aria-hidden": "true" }),
|
|
2985
|
+
h("span", { className: "ttl-project-name" }, projectLabel(project))
|
|
2986
|
+
);
|
|
2987
|
+
}
|
|
2988
|
+
function CheckIcon(props) {
|
|
2989
|
+
const checked = Boolean(props && props.checked);
|
|
2990
|
+
return h(
|
|
2991
|
+
"svg",
|
|
2992
|
+
{
|
|
2993
|
+
width: 12,
|
|
2994
|
+
height: 12,
|
|
2995
|
+
viewBox: "0 0 16 16",
|
|
2996
|
+
fill: "none",
|
|
2997
|
+
stroke: "currentColor",
|
|
2998
|
+
strokeWidth: 2,
|
|
2999
|
+
strokeLinecap: "round",
|
|
3000
|
+
strokeLinejoin: "round",
|
|
3001
|
+
"aria-hidden": "true",
|
|
3002
|
+
focusable: "false"
|
|
3003
|
+
},
|
|
3004
|
+
checked ? h("path", { d: "M3.5 8.5l3 3 6-6.5" }) : null
|
|
3005
|
+
);
|
|
3006
|
+
}
|
|
3007
|
+
function CheckButton(props) {
|
|
3008
|
+
const checked = Boolean(props && props.checked);
|
|
3009
|
+
const disabled = Boolean(props && props.disabled);
|
|
3010
|
+
const label = props && typeof props.label === "string" ? props.label : "";
|
|
3011
|
+
const hover = props && typeof props.title === "string" && props.title !== "" ? props.title : void 0;
|
|
3012
|
+
const className = props && typeof props.className === "string" && props.className !== "" ? props.className : "";
|
|
3013
|
+
const onClick = props && typeof props.onClick === "function" ? props.onClick : null;
|
|
3014
|
+
return h(
|
|
3015
|
+
"button",
|
|
3016
|
+
{
|
|
3017
|
+
type: "button",
|
|
3018
|
+
className: className === "" ? "ttl-check" : `ttl-check ${className}`,
|
|
3019
|
+
role: "checkbox",
|
|
3020
|
+
"aria-checked": checked ? "true" : "false",
|
|
3021
|
+
"aria-label": label,
|
|
3022
|
+
title: hover,
|
|
3023
|
+
"data-checked": checked ? "true" : "false",
|
|
3024
|
+
disabled,
|
|
3025
|
+
onClick
|
|
3026
|
+
},
|
|
3027
|
+
h(CheckIcon, { checked })
|
|
3028
|
+
);
|
|
2890
3029
|
}
|
|
2891
3030
|
function GanttView(props) {
|
|
2892
3031
|
const todos = props && Array.isArray(props.todos) ? props.todos : [];
|
|
@@ -3555,22 +3694,6 @@
|
|
|
3555
3694
|
)
|
|
3556
3695
|
);
|
|
3557
3696
|
};
|
|
3558
|
-
const boardCheckIcon = (completed) => h(
|
|
3559
|
-
"svg",
|
|
3560
|
-
{
|
|
3561
|
-
width: 12,
|
|
3562
|
-
height: 12,
|
|
3563
|
-
viewBox: "0 0 16 16",
|
|
3564
|
-
fill: "none",
|
|
3565
|
-
stroke: "currentColor",
|
|
3566
|
-
strokeWidth: 2,
|
|
3567
|
-
strokeLinecap: "round",
|
|
3568
|
-
strokeLinejoin: "round",
|
|
3569
|
-
"aria-hidden": "true",
|
|
3570
|
-
focusable: "false"
|
|
3571
|
-
},
|
|
3572
|
-
completed ? h("path", { d: "M3.5 8.5l3 3 6-6.5" }) : null
|
|
3573
|
-
);
|
|
3574
3697
|
const renderBoardCard = (todo) => {
|
|
3575
3698
|
const isEditing = editingId === todo.id;
|
|
3576
3699
|
const isConfirming = confirmId === todo.id;
|
|
@@ -3609,23 +3732,16 @@
|
|
|
3609
3732
|
prioritySelectControl(editingPriority, setEditingPriority, busyId === todo.id),
|
|
3610
3733
|
typeSelectControl(editingType, setEditingType, busyId === todo.id)
|
|
3611
3734
|
) : [
|
|
3612
|
-
h(
|
|
3613
|
-
"
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
disabled: isBusy,
|
|
3623
|
-
onClick: () => {
|
|
3624
|
-
void handleToggle(todo);
|
|
3625
|
-
}
|
|
3626
|
-
},
|
|
3627
|
-
boardCheckIcon(completed)
|
|
3628
|
-
),
|
|
3735
|
+
h(CheckButton, {
|
|
3736
|
+
key: "check",
|
|
3737
|
+
checked: completed,
|
|
3738
|
+
disabled: isBusy,
|
|
3739
|
+
label: t("board.checkAria", { title }),
|
|
3740
|
+
className: "ttl-board-check",
|
|
3741
|
+
onClick: () => {
|
|
3742
|
+
void handleToggle(todo);
|
|
3743
|
+
}
|
|
3744
|
+
}),
|
|
3629
3745
|
h(
|
|
3630
3746
|
"div",
|
|
3631
3747
|
{ key: "main", className: "ttl-board-card-main" },
|
|
@@ -3639,8 +3755,8 @@
|
|
|
3639
3755
|
"span",
|
|
3640
3756
|
{ className: "ttl-board-project", title: projectLabel(project) },
|
|
3641
3757
|
h("span", {
|
|
3642
|
-
className: "ttl-
|
|
3643
|
-
"data-
|
|
3758
|
+
className: "ttl-project-dot",
|
|
3759
|
+
"data-tone": projectTone(project),
|
|
3644
3760
|
"aria-hidden": "true"
|
|
3645
3761
|
}),
|
|
3646
3762
|
h("span", { className: "ttl-board-project-name" }, projectLabel(project))
|
|
@@ -4089,7 +4205,7 @@
|
|
|
4089
4205
|
|
|
4090
4206
|
// src/client/views/table.js
|
|
4091
4207
|
function createTableView(deps) {
|
|
4092
|
-
const { confirmId, detailIdOf, direction, editingId, emptyActionKey, expandedIds, filter, handleEmptyAction, handleHeaderSort, listStatus, priorityBadge, projectInput, renderActionButtons, renderDetailContent, renderFileChips, setConfirmId, sortBy, statusBadge, titleInput, toggleExpanded, typeBadge, visibleTodos } = deps;
|
|
4208
|
+
const { confirmId, detailIdOf, direction, editingId, emptyActionKey, expandedIds, filter, handleEmptyAction, handleHeaderSort, listStatus, priorityBadge, projectInput, renderActionButtons, renderDetailContent, renderFileChips, renderRowCheck, setConfirmId, sortBy, statusBadge, titleInput, toggleExpanded, typeBadge, visibleTodos } = deps;
|
|
4093
4209
|
const pushTableRow = (rows, todo) => {
|
|
4094
4210
|
const completed = todo.status === "completed";
|
|
4095
4211
|
const isEditing = editingId === todo.id;
|
|
@@ -4131,6 +4247,7 @@
|
|
|
4131
4247
|
}
|
|
4132
4248
|
}
|
|
4133
4249
|
},
|
|
4250
|
+
h("td", { className: "ttl-td ttl-td-check" }, renderRowCheck(todo)),
|
|
4134
4251
|
titleCell,
|
|
4135
4252
|
h(
|
|
4136
4253
|
"td",
|
|
@@ -4144,7 +4261,7 @@
|
|
|
4144
4261
|
),
|
|
4145
4262
|
h("td", { className: "ttl-td ttl-td-time" }, formatTime(todo.createdAt)),
|
|
4146
4263
|
h("td", { className: "ttl-td ttl-td-time" }, completed ? formatTime(todo.completedAt) : EMPTY_TIME),
|
|
4147
|
-
h("td", { className: "ttl-td ttl-td-actions" }, renderActionButtons(todo, { showDetail: true }))
|
|
4264
|
+
h("td", { className: "ttl-td ttl-td-actions" }, renderActionButtons(todo, { showDetail: true, showToggle: false }))
|
|
4148
4265
|
)
|
|
4149
4266
|
);
|
|
4150
4267
|
if (expanded) {
|
|
@@ -4207,6 +4324,11 @@
|
|
|
4207
4324
|
"aria-label": t("table.aria"),
|
|
4208
4325
|
"aria-busy": listStatus === "loading" ? "true" : "false"
|
|
4209
4326
|
},
|
|
4327
|
+
h(
|
|
4328
|
+
"colgroup",
|
|
4329
|
+
null,
|
|
4330
|
+
TABLE_COLUMNS.map((column) => h("col", { key: column.key, className: `ttl-col ttl-col-${column.key}` }))
|
|
4331
|
+
),
|
|
4210
4332
|
h(
|
|
4211
4333
|
"thead",
|
|
4212
4334
|
null,
|
|
@@ -4221,10 +4343,10 @@
|
|
|
4221
4343
|
{
|
|
4222
4344
|
key: column.key,
|
|
4223
4345
|
scope: "col",
|
|
4224
|
-
className: (column.sortBy === null ? "ttl-th" : "ttl-th ttl-th-sortable") + (column.align === "right" ? " ttl-th-right" : "")
|
|
4346
|
+
className: (column.sortBy === null ? "ttl-th" : "ttl-th ttl-th-sortable") + (column.align === "right" ? " ttl-th-right" : "") + ` ttl-th-${column.key}`,
|
|
4225
4347
|
"aria-sort": column.sortBy === null ? void 0 : ariaSort
|
|
4226
4348
|
},
|
|
4227
|
-
column.sortBy === null ? h("span", null, t(column.labelKey)) : h(
|
|
4349
|
+
column.srOnly === true ? h("span", { className: "ttl-sr-only" }, t(column.labelKey)) : column.sortBy === null ? h("span", null, t(column.labelKey)) : h(
|
|
4228
4350
|
"button",
|
|
4229
4351
|
{
|
|
4230
4352
|
type: "button",
|
|
@@ -5037,7 +5159,9 @@
|
|
|
5037
5159
|
const detailIdOf = (todo) => `ttl-detail-${String(todo.id).replace(/[^A-Za-z0-9_-]/g, "-")}`;
|
|
5038
5160
|
const statusBadge = (todo) => h(
|
|
5039
5161
|
"span",
|
|
5040
|
-
{
|
|
5162
|
+
{
|
|
5163
|
+
className: todo.status === "completed" ? "ttl-badge ttl-status-badge ttl-badge-completed" : "ttl-badge ttl-status-badge"
|
|
5164
|
+
},
|
|
5041
5165
|
t(todo.status === "completed" ? "row.completed" : "row.pending")
|
|
5042
5166
|
);
|
|
5043
5167
|
const priorityBadge = (todo) => {
|
|
@@ -5049,6 +5173,11 @@
|
|
|
5049
5173
|
className: `ttl-badge ttl-priority-badge ttl-priority-${priority}`,
|
|
5050
5174
|
"data-priority": priority
|
|
5051
5175
|
},
|
|
5176
|
+
h(
|
|
5177
|
+
"span",
|
|
5178
|
+
{ className: "ttl-priority-arrow", "aria-hidden": "true" },
|
|
5179
|
+
priority === "high" ? "↑" : priority === "medium" ? "↗" : "↓"
|
|
5180
|
+
),
|
|
5052
5181
|
t(`priority.${priority}`)
|
|
5053
5182
|
);
|
|
5054
5183
|
};
|
|
@@ -5171,22 +5300,24 @@
|
|
|
5171
5300
|
return buttons;
|
|
5172
5301
|
}
|
|
5173
5302
|
if (opts.showDetail === true) buttons.push(detailToggleButton(todo));
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5303
|
+
if (opts.showToggle !== false) {
|
|
5304
|
+
buttons.push(
|
|
5305
|
+
h(
|
|
5306
|
+
"button",
|
|
5307
|
+
{
|
|
5308
|
+
key: "toggle",
|
|
5309
|
+
type: "button",
|
|
5310
|
+
className: "ttl-link",
|
|
5311
|
+
disabled: isBusy,
|
|
5312
|
+
"aria-label": t("row.toggleAria", { action: toggleLabel, title: todo.title }),
|
|
5313
|
+
onClick: () => {
|
|
5314
|
+
void handleToggle(todo);
|
|
5315
|
+
}
|
|
5316
|
+
},
|
|
5317
|
+
toggleLabel
|
|
5318
|
+
)
|
|
5319
|
+
);
|
|
5320
|
+
}
|
|
5190
5321
|
buttons.push(
|
|
5191
5322
|
h(
|
|
5192
5323
|
"button",
|
|
@@ -5245,6 +5376,19 @@
|
|
|
5245
5376
|
}
|
|
5246
5377
|
return buttons;
|
|
5247
5378
|
};
|
|
5379
|
+
const renderRowCheck = (todo) => {
|
|
5380
|
+
const completed = todo.status === "completed";
|
|
5381
|
+
return h(CheckButton, {
|
|
5382
|
+
checked: completed,
|
|
5383
|
+
disabled: isBusy,
|
|
5384
|
+
label: t("board.checkAria", { title: todo.title === "" ? t("list.empty") : todo.title }),
|
|
5385
|
+
title: t(completed ? "row.uncomplete" : "row.complete"),
|
|
5386
|
+
className: "ttl-row-check",
|
|
5387
|
+
onClick: () => {
|
|
5388
|
+
void handleToggle(todo);
|
|
5389
|
+
}
|
|
5390
|
+
});
|
|
5391
|
+
};
|
|
5248
5392
|
const copyFilePath = (path) => {
|
|
5249
5393
|
try {
|
|
5250
5394
|
if (typeof navigator === "undefined" || navigator === null) return;
|
|
@@ -5464,6 +5608,7 @@
|
|
|
5464
5608
|
renderActionButtons,
|
|
5465
5609
|
renderDetailContent,
|
|
5466
5610
|
renderFileChips,
|
|
5611
|
+
renderRowCheck,
|
|
5467
5612
|
setBoardActionsId,
|
|
5468
5613
|
setBoardLaneCollapsed,
|
|
5469
5614
|
setBoardShowAllCompleted,
|